📄 mcs51-项目开发经典.c
字号:
// 函数功能:I2C总线启动
void i2c_start(void)
{ SCL=0;i2c_delay();//SDA只能在SCL为低时改变
SDA=1;i2c_delay();
SCL=1;i2c_delay();//SCL=1,SDA产生下降沿,则I2C启动
SDA=0;i2c_delay();
SCL=0;i2c_delay();//总线启动后时钟线为低,数据线为高
SDA=1;i2c_delay();
}
//-------------------------------------------------------------------------------------------------
// 函数功能:I2C总线停止
void i2c_stop(void)
{ SCL=0;i2c_delay();//SDA只能在SCL为低时改变
SDA=0;i2c_delay();
SCL=1;i2c_delay();//SCL=1,SDA产生上升沿,则I2C停止
SDA=1;i2c_delay();
SCL=0;i2c_delay();//总线停止后时钟线为低,数据线为高
}
//-------------------------------------------------------------------------------------------------
// 函数功能:I2C的8位写
void i2c_send8bit(uchar shu)
{ uchar i;
for(i=0;i<8;i++)
{SDA=(bit)(shu&0x80);i2c_delay();
shu=shu<<1;
SCL=1;i2c_delay();
SCL=0;i2c_delay();}
SDA=1;i2c_delay(); //数据线做读入准备
i2c_response_signal=SDA;i2c_delay();//读取应答信号
SCL=1;i2c_delay(); //发送读取时钟信号
SCL=0;i2c_delay();
}
//-------------------------------------------------------------------------------------------------
// 函数功能:I2C的8位读
uchar i2c_read8bit(void)
{ uchar i;
uchar ddate=0;
//SCL=0;//时钟线做读入准备
//SDA=1;//数据线做读入准备
//这两句是为了说明操作I2C总线的一个较让人迷惑的问题。本函数是I2C的8位读函数,
//SDA即单片机的P34脚,必须置1作为输入,而SDA置1之前,I2C总线要求SCL必须为0,否则
//I2C总线复位,所以才有这两句。为何屏蔽仍旧好使呢?因为程序中在调用i2c_read8bit()
//这个函数之前调用了i2c_send8bit()函数,而i2c_send8bit()函数调用结束退出时SDA和
//SCL的状态恰好已经是1和0。网上的很多I2C程序加了很多无畏的语句就是因为没很好的处
//理这个问题!
for(i=0;i<8;i++)
{ddate<<=1;
SCL=1;i2c_delay();
ddate|=SDA;i2c_delay();
SCL=0;i2c_delay();
}
return ddate;
}
//-------------------------------------------------------------------------------------------------
// 函数功能:I2C应答
void i2c_ack(void)
{ SCL=0;i2c_delay();
SDA=0;i2c_delay(); //SDA=0应答,
SCL=1;i2c_delay();
SCL=0;i2c_delay();
SDA=1;i2c_delay();
}
//=================================================================================================
// 24C02驱动程序
//=================================================================================================
// 函数功能:I2C总线器件24C02的单字节写入
// 形参:data_addr表示要写入的地址、data_write表示要写入的数据
void sendbyte_24c02(uchar data_addr,uchar data_write)
{ i2c_start();
i2c_send8bit(0xA0);
i2c_send8bit(data_addr);
i2c_send8bit(data_write);
i2c_stop();
while(1)//应答查询,判断写操作完成
{i2c_response_signal=1;
i2c_start();
i2c_send8bit(0xA0);
if(i2c_response_signal==0) break;
}
}
//-------------------------------------------------------------------------------------------------
// 函数功能:I2C总线器件24C02的单字节读取
// 形参:data_addr表示要读取数据的存储地址
uchar readbyte_24c02(uchar data_addr)
{ uchar return_data;
i2c_start();
i2c_send8bit(0xA0);
i2c_send8bit(data_addr);
i2c_start();
i2c_send8bit(0xA1);
return_data=i2c_read8bit();
i2c_stop();
return (return_data);
}
//=================================================================================================
// SD2000驱动程序
//=================================================================================================
// SD2000读出和写入的时间数据必须是BCD码格式
// 举例:2007年、5月、23日、星期3、11时、34分、18秒 的具体表示方法如下:
// year =0x04;
// month =0x02;
// date =0x21;
// week =0x06;
// hour =0x15;
// minute=0x04;
// second=0x00;
//-------------------------------------------------------------------------------------------------
// 函数功能:时钟数据高低位调换,这是SD2000A芯片操作的唯一麻烦
uchar reverse_byte_hl(uchar clock_data)
{ bit temp_bit;
bit_byte=clock_data;
temp_bit=bit_byte_0;
bit_byte_0=bit_byte_7;
bit_byte_7=temp_bit;
temp_bit=bit_byte_1;
bit_byte_1=bit_byte_6;
bit_byte_6=temp_bit;
temp_bit=bit_byte_2;
bit_byte_2=bit_byte_5;
bit_byte_5=temp_bit;
temp_bit=bit_byte_3;
bit_byte_3=bit_byte_4;
bit_byte_4=temp_bit;
bit_byte=bit_byte;//important
return (bit_byte);
}
//-------------------------------------------------------------------------------------------------
// 函数功能:设定SD2000A状态及时间写入
void set_sd2000(void)
{ i2c_start();
i2c_send8bit(0x60);//发送SD2000A复位命令
i2c_stop();
i2c_start();
i2c_send8bit(0x62);//发送写SD2000A状态寄存器命令
i2c_send8bit(reverse_byte_hl(0xc0));//24小时进制,关所有中断输出
i2c_stop();
i2c_start();
i2c_send8bit(0x64);//发送写时钟数据1命令
i2c_send8bit(reverse_byte_hl(year));
i2c_send8bit(reverse_byte_hl(month));
i2c_send8bit(reverse_byte_hl(date));
i2c_send8bit(reverse_byte_hl(week));
i2c_send8bit(reverse_byte_hl(hour));
i2c_send8bit(reverse_byte_hl(minute));
i2c_send8bit(reverse_byte_hl(second));
i2c_stop();
}
//-------------------------------------------------------------------------------------------------
// 函数功能:从SD2000A读取当前时间,从年到秒
void read_sd2000_ys(void)
{ i2c_start();
i2c_send8bit(0x65);//发送"读时钟数据1"命令
year=i2c_read8bit();
i2c_ack();
month=i2c_read8bit();
i2c_ack();
date=i2c_read8bit();
i2c_ack();
week=i2c_read8bit();
i2c_ack();
hour=i2c_read8bit();
i2c_ack();
minute=i2c_read8bit();
i2c_ack();
second=i2c_read8bit();
i2c_stop();
year =reverse_byte_hl(year);
month =reverse_byte_hl(month);
date =reverse_byte_hl(date);
week =reverse_byte_hl(week);
hour =reverse_byte_hl(hour)&0x7f;//调整hour数据
minute=reverse_byte_hl(minute);
second=reverse_byte_hl(second);
}
//=================================================================================================
// 串口UART操作相关程序
//=================================================================================================
//函数功能:串口发射1个字节
void uart_byte_out(uchar uart_data_out)
{ SBUF = uart_data_out;
while(TI==0);
TI=0;
}
//-------------------------------------------------------------------------------------------------
//函数功能:串口发射字符数组。通常将要发送的字符数组定义在CODE代码区。
void uart_string_out(char * char_array)
{ uchar i;
for(i=0; i<strlen(char_array) ;i++)
{
uart_byte_out(char_array[i]);
}
}
//-------------------------------------------------------------------------------------------------
//函数功能:串口输出数据十进制到PC机屏幕上
//形参:范围 0-65535 ;例如:data_to_out=12345(或0x3039),则计算机屏幕就显示12345
void uart_data_decimalist_out(uint data_to_out)
{ bit entrance;
uchar ge,shi,bai,qian,wan;
wan = (data_to_out/10000) ;//拆分万位,并转化为ASKII码
qian = (data_to_out%10000)/1000;//拆分千位,并转化为ASKII码
bai = (data_to_out%1000)/100 ;//拆分百位,并转化为ASKII码
shi = (data_to_out%100)/10 ;//拆分十位,并转化为ASKII码
ge = (data_to_out%10) ;//拆分个位,并转化为ASKII码
entrance=1;//开放个、十、百、千、万的判断传输入口
if(wan && entrance)
{uart_byte_out(change_hex_to_askii(wan));
uart_byte_out(change_hex_to_askii(qian));
uart_byte_out(change_hex_to_askii(bai));
uart_byte_out(change_hex_to_askii(shi));
uart_byte_out(change_hex_to_askii(ge));
entrance=0;//如果万位不为0,则不再判断其它位
}
else if(qian && entrance)
{uart_byte_out(change_hex_to_askii(qian));
uart_byte_out(change_hex_to_askii(bai));
uart_byte_out(change_hex_to_askii(shi));
uart_byte_out(change_hex_to_askii(ge));
entrance=0;//如果千位不为0,则不再判断其它位
}
else if(bai && entrance)
{uart_byte_out(change_hex_to_askii(bai));
uart_byte_out(change_hex_to_askii(shi));
uart_byte_out(change_hex_to_askii(ge));
entrance=0;//如果百位不为0,则不再判断其它位
}
else if(shi && entrance)
{uart_byte_out(change_hex_to_askii(shi));
uart_byte_out(change_hex_to_askii(ge));
entrance=0;//如果十位不为0,则不再判断其它位
}
else
{uart_byte_out(change_hex_to_askii(ge));
}
}
//-------------------------------------------------------------------------------------------------
// 函数功能:串口显示的回车换行
// 形参:newline_number 表示一共换几行
void uart_newline(uchar newline_number)
{ uchar i;
for(i=0;i<newline_number;i++)
{
uart_byte_out(0x0d);
uart_byte_out(0x0a);
}
}
//-------------------------------------------------------------------------------------------------
// 函数功能:串口显示的空格
// 形参:space_number 表示空几个格
void uart_space(uchar space_number)
{ uchar i;
for(i=0;i<space_number;i++)
{
uart_byte_out(0x20);
}
}
//=================================================================================================
// CSI93C46操作子程序
// 注意:这里使用的CSI93C46为16位结构的EEROM
//=================================================================================================
/***********************************************************************/
/*名称: START_93C46()
/*说明: 用于93C46的启动,防止由于CS_93C46的改动而引起数据时序混乱
/***********************************************************************/
void START_93C46()
{uint num=1000;
DO_93C46=1; /*防止DO由于是低电平而无法输入*/
CS_93C46=1;
/*开启93C46*/
CS_93C46=0;
DI_93C46=0;
SK_93C46=0;
CS_93C46=1;
while(num!=0){num=num-1;}
}
/***************************************************************************/
/*名称:END_93C46() */
/*说明:用于93C46的结束,防止由于CS_93C46的改动而引起数据线为0而无法输入*/
/***************************************************************************/
void END_93C46()
{
CS_93C46=0;
DI_93C46=1;
SK_93C46=1;
}
/***********************************************************************/
/*名称:SEND_DATA_93C46() */
/*说明:在93C46启动下,送入指定位数的数据 */
/*输入: op_data 要输入的数据 */
/* num 输入的位数 */
/**********************************************************************/
void SEND_DATA_93C46(unsigned int op_data,unsigned char num)
{data unsigned char temp1;
op_data=op_data<<(16-num); /*左移去掉无用位*/
for(temp1=0;temp1<num;temp1++)
{if( (op_data&0X8000)==00 ){DI_93C46=0;}
else{DI_93C46=1;}
SK_93C46=1;SK_93C46=1;SK_93C46=1;SK_93C46=1;
SK_93C46=0;
op_data=op_data<<1;
}
}
/***********************************************************************/
/*名称: EWEN_93C46() */
/*说明: 93C46的编程启动.操作码(100 11XXXX) */
/***********************************************************************/
void EWEN_93C46()
{
START_93C46();
SEND_DATA_93C46(0X04,0X03); /*送入3位操作码*/
SEND_DATA_93C46(0X30,0X06); /*送入6位地址*/
END_93C46();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -