51单片机C语言编程实例2.docx
《51单片机C语言编程实例2.docx》由会员分享,可在线阅读,更多相关《51单片机C语言编程实例2.docx(52页珍藏版)》请在冰豆网上搜索。
51单片机C语言编程实例2
【实例86】
总线接口的软件实现
/*引脚定义和相关头文件包含*/
#include
sbitI2C_SDA=P1^0;
sbitI2C_SCL=P1^1;
(1)函数voiddelay()
在C51中使用nop指令,实现一段时间的延时,程序代码如下:
voiddelay(void)
{
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
}
(2)函数voidi2c_start()
voidi2c_start(void)
{
I2C_SDA=1;
I2C_SCL=1;
delay();
I2C_SDA=0;
delay();
I2C_SCL=0;
}
(3)函数voidi2c_stop()
voidi2c_stop(void)
{
I2C_SDA=0;
I2C_SCL=1;
delay();
I2C_SDA=1;
delay();
I2C_SCL=0;
}
(4)函数voidi2c_ack()
voidi2c_ack(void)
{
I2C_SDA=0;
I2C_SCL=1;
delay();
I2C_SDA=1;
I2C_SCL=0;
}
(5)voidi2c_send_byte()
/*输入参数:
c*/
voidi2c_send_byte(unsignedcharc)
{
unsignedchari;
for(i=8;i>0;i--)
{
if(c&0x80)I2C_SDA=1;
elseI2C_SDA=0;
I2C_SCL=1;
delay();
I2C_SCL=0;
c=c<<1;
}
I2C_SDA=1;
/*释放数据线,准备接收应答信号*/
I2C_SCL=1;
delay();
while(!
(0==I2C_SDA
/*等待应答信号*/
&&1==I2C_SCL));
}
(6)函数unsignedchari2c_recv_byte()
/*输入参数:
c*/
/*返回数值:
从总线上读取的数据*/
unsignedchari2c_recv_byte(void)
{
unsignedchari;
unsignedcharr;
I2C_SDA=1;
for(i=8;i>0;i--)
{
r=r<<1;
/*左移补0*/
I2C_SCL=1;
delay();
if(I2C_SDA)r=r|0x01;
/*当数据线为高时,数据位为1*/
I2C_SCL=0;
}
returnr;
}
【实例87】SPI总线接口的软件实现
程序中端口宏定义如下:
#include
#include
#defineWREN0x06
/*设置写使能锁存器*/
#defineWRDI0x04
/*复位写使用锁存器*/
#defineRSDR0x05
/*读状态寄存器*/
#defineWRSR0x01
/*写状态寄存器(看门狗和块锁)*/
#defineREAD0x03
/*/读操作指令0000A8011*/
#defineWRITE0x02
/*写操作指令0000A8010*/
#defineWIP0x01
/*状态寄存器中写操作是否忙*/
/*各引脚定义*/
sbitX5045_SO=P1^1;
sbitX5045_SI=P1^6;
sbitX5045_SCK=P1^4;
sbitX5045_CS=P1^2;
(1)函数voidwrite_byte()
/*入口:
byte,要写入的8位数据*/
voidwrite_byte(unsignedcharbyte)
{
unsignedchari;
unsignedchartmp;
for(i=0;i<8;i++)
{
X5045_SCK=0;
tmp=byte&0x80;
if(tmp==0x80)
/*与0X80比较判断最高数据位是否为1*/
{
X5045_SI=1;
_nop_();
}
else
{
X5045_SI=0;
_nop_();
}
X5045_SCK=1;
byte=byte<<1;
}
}
(2)函数unsignedcharread_byte()
/*返回值:
从X5045中读取的8位数据*/
unsignedcharread_byte(void)
/*读数据,一次8位*/
{
unsignedchari;
unsignedcharbyte=0;
for(i=8;i>0;i--)
{
byte=byte<<1;
/*先读出的是高位*/
X5045_SCK=1;
_nop_();
_nop_();
X5045_SCK=0;
_nop_();
_nop_();
byte=byte|(unsignedchar)X5045_SO;
}
return(byte);
}
(3)函数voidx5045_start()和voidx5045_stop()
voidx5045_start(void)
{
X5045_CS=1;
_nop_();
_nop_();
X5045_SCK=0;
_nop_();
_nop_();
X5045_CS=0;
_nop_();
_nop_();
}
voidx5045_end(void)
{
X5045_SCK=0;
_nop_();
_nop_();
X5045_CS=1;
_nop_();
_nop_();
}
(4)函数unsignedcharx5045_read_status()
unsignedcharx5045_read_status(void)
{
unsignedchartmp;
x5045_start();
write_byte(RSDR);
tmp=read_byte();
x5045_end();
returntmp;
}
(5)函数voidx5045_write_status()
voidx5045_write_status(unsignedcharstatus)
{
unsignedchartmp;
/*写操作之前先使能写操作*/
x5045_start();
write_byte(WREN);
x5045_end();
/*写入状态寄存器*/
x5045_start();
write_byte(WRSR);
write_byte(status);
x5045_end();
/*检查写操作是否完成*/
do
{
x5045_start();
write_byte(RSDR);
/*RSDRreadstatusregesiter*/
tmp=read_byte();
x5045_end();
}
while(tmp&WIP);
}
(6)函数unsignedcharread_addr_data()
/*函数入口:
addr,要读取数据的地址*/
unsignedcharread_addr_data(unsignedintaddr)
{
unsignedcharaddr_tmp,tmp;
unsignedcharread_cmd;
if(addr>255)read_cmd=READ|0X08;
/*如果超出了一页,则名字字节A8为1*/
elseread_cmd=READ;
addr_tmp=(unsignedchar)(addr&0xff);
x5045_start();
write_byte(read_cmd);
write_byte(addr_tmp);
tmp=read_byte();
x5045_end();
returntmp;
}
(7)函数voidwrite_addr_data()
/*入口地址:
addr,要写入数据的地址*/
voidwrite_addr_data(unsignedintaddr,unsignedcharedata)
{
unsignedchartmp,addr_tmp;
unsignedcharcmd_tmp;
/*写使能操作*/
x5045_start();
write_byte(WREN);
x5045_end();
/*地址和写操作指令调节*/
if(addr>255)cmd_tmp=WRITE|0x08;
elsecmd_tmp=WRITE;
addr_tmp=(unsignedchar)(addr&0xff);
/*向指定地址写入数据*/
x5045_start();
write_byte(cmd_tmp);
write_byte(addr_tmp);
write_byte(edata);
x5045_end();
/*检查写操作是否完成*/
do
{
x5045_start();
write_byte(RSDR);
tmp=read_byte();
x5045_end();
}
while(tmp&WIP);
}
(8)函数voidreset_wdt()
voidreset_wdt(void)
{
X5045_CS=0;
_nop_();
_nop_();
X5045_CS=1;
nop_();
_nop_();
}
【实例88】1-WIRE总线接口的软件实现
(1)函数void_1wire_init()
/*包含头文件*/
#include
#include
/*引脚定义*/
sbitDQ=P1^2;
/*函数名称:
单总线初始化*/
voidinit(void)
{
unsignedchari;
DQ=1;
DQ=0;
for(i=200;i>0;i--)_nop_();
/*延时约600μs*/
DQ=1;
for(i=10;i>0;i--)_nop_();
/*延时约30μs*/
while(DQ==1);
for(i=100;i>0;i--)_nop_();
/*延时约300μs*/
DQ=1;
}
(2)函数voidwrite_bit_1()
voidwrite_bit_1(void)
{
unsignedchari;
DQ=1;
DQ=0;
for(i=25;i>0;i--)_nop_();
/*延时约90μs*/
DQ=1;
}
(3)函数voidwrite_bit_0()
voidwrite_bit_0(void)
{
unsignedchari;
DQ=1;
DQ=0;
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
DQ=1;
for(i=25;i>0;i--)_nop_();
/*延时约90μs*/
}
(4)另外仔细观察1-WIRE总线的写时序图,可将写“1”和写“0”合为一个函数。
voidwrite_bit(bitD)
{
unsignedchari;
DQ=1;
DQ=0;
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
DQ=D
for(i=25;i>0;i--)_nop_();
/*延时约90us*/
DQ=1;
}
(5)函数bitread_bit()
bitread_bit(void)
{
unsignedchari;
DQ=0;
for(i=0;i<5;i++)_nop_();
if(DQ==1)
{
return1;
}
else
{
return0;
}
}
(6)函数voidwrite_byte()
voidwrite_byte(unsigendcharbyte)
{
unsignedchari;
unsignedchartmp;
tmp=byte&0x01
for(i=0;i<8;i++)
{
tmp=byte>>i;
/*将要写的数据字节右移i位*/
tmp&=0x01;
/*得到数据字节的第i位*/
write_bit((bit)tmp);
}
}
(7)函数unsignedcharread_byte()
unsignedcharread_byte(void)
{
unsignedchari;
unsignedchartmp;
.
tmp=0;
/*将返回值初始化为0*/
for(i=0;i<8;i++)
{
if(read_bit())
/*如果当前读取的数据位为1*/
{
tmp=tmp|(0x01<
/*将返回字节对应的数据位置为1*/
}
}
for(i=0;i<20;i++)_nop_();
/*等待时序结束*/
}
【实例89】单片机外挂CAN总线接口
SJA1000_Config_Normal()
{
BTR0=0x00;
BTR1=0x14;
/*设置为1M波特率通信*/
SJAEntryResetMode();
/*进入复位模式*/
WriteSJAReg(REG_CAN_CDR,0xc8);
/*配置时钟分频寄存器,选择PeliCAN模式*/
WriteSJAReg(REG_CAN_MOD,0x05);
/*配置模式寄存器,选择双滤波、自发自收模式*/
WriteSJARegBlock(16,Send_CAN_Filter,8);
/*配置验收代码/屏蔽寄存器*/
WriteSJAReg(REG_CAN_BTR0,BTR0);
/*配置总线定时器0x00*/
WriteSJAReg(REG_CAN_BTR1,BTR1);
/*配置总线定时器0x14*/
WriteSJAReg(REG_CAN_OCR,0x1a);
/*配置输出管脚,推挽输出。
*/
SJAQuitResetMode();
/*退出复位模式,进入工作模式*/
}
报文发送程序如下所示:
/*==============================================================*/
/*函数原型:
bitBCAN_DATA_WRITE(unsignedchar*SendDataBuf)*/
/*参数说明:
特定帧各式的数据*/
/*返回值:
*/
/*0;表示将数据成功的送至发送缓冲区*/
/*1;表示上一次的数据正在发送,*/
/*说明:
将待发送特定帧各式的数据,送入SJA1000发送缓存区中,然后启动*/
/*SJA1000发送。
*/
/*特定帧格式为:
开始的两个字节存放'描述符',以后的为数据*/
/*描述符包括11位长的ID(标志符)\1位RTR\4位描述数据长度的DLC共16位*/
/*注:
本函数的返回值仅指示,将数据正确写入SJA1000发送缓存区中与否。
*/
/*不指示SJA1000将该数据正确发送到CAN总线上完毕与否*/
/*================================================================*/
bitBCAN_DATA_WRITE(unsignedchar*SendDataBuf)
{
unsignedcharTempCount;
SJA_BCANAdr=REG_STATUS;
/*访问地址指向状态寄存器*/
if((*SJA_BCANAdr&0x08)==0)
/*判断上次发送是否完成*/
{
return1;
}
if((*SJA_BCANAdr&0x04)==0)
/*判断发送缓冲区是否锁定*/
{
return1;
}
SJA_BCANAdr=REG_TxBuffer1;
/*访问地址指向发送缓冲区1*/
if((SendDataBuf[1]&0x10)==0)
/*判断RTR,从而得出是数据帧还是远程帧*/
{
TempCount=(SendDataBuf[1]&0x0f)+2;
/*输入数据帧*/
}
else
{
TempCount=2;
/*远程帧*/
}
memcpy(SJA_BCANAdr,SendDataBuf,TempCount);
return0;
}
报文接收程序如下所示:
/*==============================================================*/
/*函数原型:
bitBCAN_DATA_WRITE(unsignedchar*SendDataBuf)*/
/*参数说明:
特定帧各式的数据*/
/*返回值:
*/
/*0;表示将数据成功的送至发送缓冲区*/
/*1;表示上一次的数据正在发送,*/
/*说明:
将待发送特定帧各式的数据,送入SJA1000发送缓存区中,然后启动*/
/*SJA1000发送。
*/
/*特定帧格式为:
开始的两个字节存放'描述符',以后的为数据*/
/*描述符包括11位长的ID(标志符)\1位RTR\4位描述数据长度的DLC共16位*/
/*注:
本函数的返回值仅指示,将数据正确写入SJA1000发送缓存区中与否。
*/
/*不指示SJA1000将该数据正确发送到CAN总线上完毕与否*/
/*================================================================*/
bitBCAN_DATA_WRITE(unsignedchar*SendDataBuf)
{
unsignedcharTempCount;
SJA_BCANAdr=REG_STATUS;
/*访问地址指向状态寄存器*/
if((*SJA_BCANAdr&0x08)==0)
/*判断上次发送是否完成*/
{
return1;
}
if((*SJA_BCANAdr&0x04)==0)
/*判断发送缓冲区是否锁定*/
{
return1;
}
SJA_BCANAdr=REG_TxBuffer1;
/*访问地址指向发送缓冲区1*/
if((SendDataBuf[1]&0x10)==0)
/*判断RTR,从而得出是数据帧还是远程帧*/
{
TempCount=(SendDataBuf[1]&0x0f)+2;
/*输入数据帧*/
}
else
{
TempCount=2;
/*远程帧*/
}
memcpy(SJA_BCANAdr,SendDataBuf,TempCount);
return0;
}
【实例90】单片机外挂USB总线接口
unsignedcharcodeDeviceDescriptor[]=
{
18,/*bLength,长度(18字节)*/
1,/*bDescriptorType,描述符类型,1代表设备描述符*/
0x10,1,/*bcdUSB,USB规范版本1.1,以BCD码表示*/
0,/*bDeviceClass,设备类码*/
0,/*bDeviceSubClass,设备子类码*/
1,/*bDeviceProtocol,设备协议*/
16,/*bMaxPacketSize0,最大封包大小*/
0xff,0xff,/*idVendor,制造商ID,每个厂商有不同的ID,这里未定义*/
0,1,/*idProduct,产品ID,每个厂商为自己生产的不同产品定义*/
0,0,/*bcdDevice,发行序号,以BCD码表示*/
1,/*iManufacturer,制造商的字符串描述符索引*/
2,/*iProduct,产品的字符串描述符索引*/
0,/*iSerialNumber,设备序号的字符串描述符索引*/
1,/*bNumConfigurations,配置描述符的个数*/
};
CH375初始化程序如下:
#defineCH375HM_INT_ENEX0
/*单片机的INT0引脚的中断使能*/
#defineCH375HM_INT_FLAGIE0
/*单片机的INT0引脚的中断标志*/
/*其他程序代码*/
/*假定CH375模块的INT#引脚连接到单片机的INT0引脚*/
IT0=1;
/*置CH375模块中断信号为下降沿触发,实际上,电平触发方式也可以*/
CH375HM_INT_FLAG=0;
/*清中断标志*/
CH375HM_INT_EN=1;
/*允许CH375模块中断*/
CH375提供的开放的命令库函数如下:
#defineCH375HM_INDEX_WR(Index)
{
CH375HM_INDEX=(Index);
}
/*写索引地址*/
#defineCH375HM_DATA_WR(Data)
{
CH375HM_DATA=(Data);
}
/*写数据*/
#defineCH375HM_DATA_RD()(CH375HM_DATA)
/*读数据*/
/*其他程序代码*/