27,382
社区成员
发帖
与我相关
我的任务
分享
以下是我当初学习串口通信的功能比较全的代码,楼主可以参考下,去掉一些不用的就行了
#include<reg52.h>
#include<stdio.h>
// #include<inrins.h>
#define unint unsigned int
#define unchar unsigned char
#define PCF8591_WRITE 0x90 //本机的PCF8591芯片地址为 1001 0000 即为低四位的前三位为000.不同开发板可能不同
#define PCF8591_READ 0x91
unchar ge,shi,bai,idata receive_da, flg,flg1,ad_p,flg_on,ReData,t0_num;
unint D[10];
unchar AD_CHANNEL;
sbit SDA=P2^1;
sbit SCL=P2^0;
sbit dula=P1^0;
sbit LS138A=P2^2;
sbit LS138B=P2^3;
sbit LS138C=P2^4;
float ad_vo;
unchar code Disp_Tab[]={
0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x67,0x7c,
0x39,0x5e,0x79,0x71
};
init1() //串口初始化
{
SCON = 0x50; //REN=1允许串行接受状态,串口工作模式1
TMOD|= 0x21; //定时器1工作方式2,定时器2
PCON|= 0x80; //电源管理寄存器用于波特率是否加倍
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
TH1 = 0xF3; // //baud*2 /* 波特率4800、数据位8、停止位1。效验位无 (12M)
TL1 = 0xF3;
TR1 = 1;
ES = 1; //开串口中断
EA = 1; // 开总中断
ET0=1; //开定时器0中断
}
void delay() //响应函数
{ ; ; }
void init() //总线初始化函数
{
SDA=1;
delay();
SCL=1;
delay();
}
void iic_start() //启动函数
{
SDA=1;
delay();
SCL=1;
delay();
SDA=0;
delay();
/*SCL=0;
delay(); */
}
void STOP_I2C() //停止信号
{
SDA=0;
delay();
SCL=1;
delay();
SDA=1;
delay();
}
void ACK_I2c() // 应答
{
unint i;
SCL=1;
delay();
while((SDA=1)&&(i<255)) i++;
SCL=0;
delay();
}
void NOACK_I2c() //非应答
{
SCL=1;
delay();
SDA=0;
SCL=0;
delay();
}
void write_byte(unchar date )
{
unchar i,temp;
temp=date;
for(i=0;i<8;i++)
{
temp=temp<<1;
SCL=0;
delay();
SDA=CY;
delay();
SCL=1;
delay();
}
// SCL=1; 调试时的错误
SCL=0;
delay();
SDA=1;
delay();
SCL=1;
delay();
}
unchar read_byte()
{
unchar k,j;
SCL=0; // 为下一步SDA=1作准备
delay();
SDA=1;//置“读取数据”模式
delay();
//以便数据变化
for(j=0;j<8;j++)
{
SCL=1;///让数据稳定才能读操作
delay();
k=(k<<1)|SDA;
SCL=0;//完成一个时钟
delay();
}
return k;
}
unchar ADC_PCF8591(unchar controlbyte) //完整的AD转换函数,注意要先写后读
{
unchar c,i=0;
iic_start();
write_byte(PCF8591_WRITE);
ACK_I2c();
write_byte(controlbyte); //控制字
ACK_I2c();
iic_start();
write_byte(PCF8591_READ);
ACK_I2c();
c=read_byte();
NOACK_I2c();
STOP_I2C();
return(c); //返回读的数据
}
deplay()
{ unchar i,j;
unchar LedOut[8];
/********以下AD-DA处理*************/
switch(AD_CHANNEL)
{
case 0:
D[0]=ADC_PCF8591(0x41); //ADC0 模数转换1
break;
case 1:
D[1]=ADC_PCF8591(0x42); //ADC1 模数转换2
break;
case 2:
D[2]=ADC_PCF8591(0x43); //ADC2 模数转换3
break;
case 3:
D[3]=ADC_PCF8591(0x40); //ADC3 模数转换4
break;
// case 4: DACconversion(0x90,0x40, D[4]/4); //DAC 数模转换
// break;
}
// D[4]=400; //数字--->>模拟输出
//D[4]=D[0]; // 把模拟输入 采样的信号 通过数模转换输出
if(++AD_CHANNEL>4) AD_CHANNEL=0;
/********以下将AD的值送到LED数码管显示,本程序只使用了两个通道即D1和D2*************/
LedOut[0]=Disp_Tab[D[0]%10000/1000];
LedOut[1]=Disp_Tab[D[0]%1000/100];
LedOut[2]=Disp_Tab[D[0]%100/10];
LedOut[3]=Disp_Tab[D[0]%10];
LedOut[4]=Disp_Tab[0];
LedOut[5]=Disp_Tab[0];
LedOut[6]=Disp_Tab[0];
LedOut[7]=Disp_Tab[0];
/*D[0]才是数码转换后的数据*/
for( i=0; i<8; i++)
{ P0 = LedOut[i];
switch(i) //使用switch 语句控制138译码器 也可以是用查表的方式 学员可以试着自己修改
{
case 0:LS138A=0; LS138B=0; LS138C=0; break;
case 1:LS138A=1; LS138B=0; LS138C=0; break;
case 2:LS138A=0; LS138B=1; LS138C=0; break;
case 3:LS138A=1; LS138B=1; LS138C=0; break;
case 4:LS138A=0; LS138B=0; LS138C=1; break;
case 5:LS138A=1; LS138B=0; LS138C=1; break;
case 6:LS138A=0; LS138B=1; LS138C=1; break;
case 7:LS138A=1; LS138B=1; LS138C=1; break;
}
for (j = 0 ; j<90 ;j++) { ;} //扫描间隔时间
}
P0 = 0;
}
void ser_int (void) interrupt 4 using 1
{
RI = 0; //清除RI接受中断标志
ReData = SBUF; //在电脑上点击发送按钮即将数据发送给单片机,flag=1表示单片机接收到了上位机发送的数据
// SenData=ReData;
flg1=1;
if(ReData ==1)
flg_on=0;
else if(ReData ==2)
flg_on=1;
else
flg_on=2;
}
void T0_time()interrupt 1 //定时1S使flg=1
{
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
t0_num++;
if(t0_num==20)
{
t0_num=0;
flg=1;
}
}
void main()
{
init1();//串口初始化
init();
while(1)
{
if(flg1==1)//串口中断信号
{
flg1=0;
ES=0;
TI=1;
switch(flg_on)
{
case 2:puts("Turn on ad!\n");
TR0=1;//启动定时器T0便于后面每秒发送一次数据
//TF0=1;
flg=1;
break;
case 1:printf("Turn off ad!\n");
TR0=0;
break;
case 0:puts("Error\n");
TR0=0;
break;
}
while(TI==0);
TI=0;
ES=1;
}
if(flg==1)
{
flg=0;
ad_p=D[0];//此处是将ad转换后的数据赋给ad_p
ad_vo=(float)ad_p*5.0/255;
ES=0;
TI=1;
printf("The volage is %fV\n",ad_vo);
while(TI==0);
TI=0;
ES=1;
//TF0=0;
}
deplay();
}
}
/*本程序已经成功显示了实际电压值,以及转换后的3位十进制数,用到了AD转换,数码显示等知识点*/