赞
踩
本文较少涉及硬件与时序,主要从代码层面记录蓝桥杯单片机对DS1302、DS18B20、PCF8591、AT24C02模块的使用
目录
硬件连接我们仅关注三个引脚:SCK(时钟信号线)、SDA(数据线、RST(芯片使能)。
寄存器:
时序图:
ds1302.c底层驱动:
- #include "ds1302.h"
- #include <reg52.h>
- #include <intrins.h>
-
- sbit SCK = P1^7;
- sbit SDA = P2^3;
- sbit RST = P1^3;
-
-
- //写字节,上升沿有效
- void Write_Ds1302(unsigned char temp)
- {
- unsigned char i;
- for (i=0;i<8;i++)
- {
- SCK = 0;
- SDA = temp&0x01;//从低位一位一位向右移动
- temp>>=1;
- SCK=1;
- }
- }
-
- //向DS1302寄存器写入数据
- void Write_Ds1302_Byte( unsigned char address,unsigned char dat )
- {
- RST=0; _nop_();
- SCK=0; _nop_();
- RST=1; _nop_();
- Write_Ds1302(address); //传入地址(一个字节)
- Write_Ds1302(dat); //后传入数据(一个字节)
- RST=0;
- }
-
- //从DS1302寄存器读出数据
- unsigned char Read_Ds1302_Byte ( unsigned char address )
- {
- unsigned char i,temp=0x00;
- RST=0; _nop_();
- SCK=0; _nop_();
- RST=1; _nop_();
- Write_Ds1302(address);//写入地址
- for (i=0;i<8;i++) //写入数据,上升沿有效,数据先来 上升沿后来
- {
- SCK=0;
- temp>>=1;
- if(SDA)
- temp|=0x80; //从高位到低位,一位一位右移
- SCK=1;
- }
- RST=0; _nop_();
- SCK=0; _nop_();
- SCK=1; _nop_();
- SDA=0; _nop_();
- SDA=1; _nop_();
- return (temp);
- }
-

需要我们在DS1302.c写的函数:
- //向芯片写入时分秒
- void Set_Rtc(unsigned char* ucRtc)
- {
- unsigned char i;
- Write_Ds1302_Byte(0x8e,0x00);//关闭写保护:向0x8E写入0x00
- for(i=0;i<3;i++)//依次写入时分秒
- Write_Ds1302_Byte(0x84-2*i,ucRtc[i]);//地址依次为0x84,0x82,0x80
- Write_Ds1302_Byte(0x8e,0x80);//打开写保护:向0x8E写入0x80
- }
- //读出芯片的时分秒
- void Read_Rtc(unsigned char* ucRtc)
- {
- unsigned char i;
- for(i=0;i<3;i++)//依次读出时分秒
- ucRtc[i] = Read_Ds1302_Byte(0x85-2*i);//地址依次为0x85,0x83,0x81
- }

主函数的处理:
- #include <ds1302.h>//时钟驱动专用头文件
- ...
- ...
- ...
- unsigned char ucRtc[3] = {0x23,0x59,0x55};//时钟数据存放数组 默认时间 23:59:55
- ...
- ...
- ...
- void Seg_Proc()
- {
- if(Seg_Slow_Down) return;
- Seg_Slow_Down = 1;//数码管减速程序
-
- /* 信息读取区域 */
- Read_Rtc(ucRtc);//实时读取时钟数据
-
- /* 数据处理区域 */
- Seg_Buf[0] = ucRtc[0] / 16;
- Seg_Buf[1] = ucRtc[0] % 16;
- Seg_Buf[2] = 11;//Seg_Dula[11]=0xbf,代表间隔符
- Seg_Buf[3] = ucRtc[1] / 16;
- Seg_Buf[4] = ucRtc[1] % 16;
- Seg_Buf[5] = 11;
- Seg_Buf[6] = ucRtc[2] / 16;
- Seg_Buf[7] = ucRtc[2] % 16;
- }
-
- void main()
- {
- System_Init();
- Timer0Init();
- Set_Rtc(ucRtc);//上电时设置时间
- while (1)
- {
- Key_Proc();
- Seg_Proc();
- Led_Proc();
- }
- }

注:由于DS1302存储数据的形式是8421BCD码,而数码管显示的形式是十进制(若第i个数码管显示9,Seg_Buf[i]=9),所以存在一个问题:若不进行转换,9(0000 1001)结束后显示16(0001 0000).
8421BCD码转十进制:DEC=BCD/16*10+BCD%16(2位BCD)
十进制转8421BCD码:BCD=DEC/10*16+DEC%10(2位BCD)
所以,在DS1302数据显示时,进行/16、%16操作;而在往DS1302写数据时ucRtc[]内的数据即为8421BCD码。
硬件连接我们仅关注DQ(数据通信线,外接上拉电阻)
高速暂存器(9个字节)
第0、1字节:
高五位为符号位,温度为正S=1;温度为负S=0。
配置寄存器:
初始化时序:
读写时序:
ds18b20.c底层代码:
- #include "onewire.h"
- #include "reg52.h"
-
- sbit DQ = P1^4;
-
-
- //单总线内部延时函数
- void Delay_OneWire(unsigned int t)
- {
- t*=12;//如果不写这一句的话,上电温度显示55.9
- while(t--);
- }
-
- //单总线写操作
- void Write_DS18B20(unsigned char dat)
- {
- unsigned char i;
- for(i=0;i<8;i++)
- {
- DQ = 0;
- DQ = dat&0x01;//从低位到高位一位一位写
- Delay_OneWire(5);
- DQ = 1;
- dat >>= 1;
- }
- Delay_OneWire(5);
- }
-
- //单总线读操作
- unsigned char Read_DS18B20(void)
- {
- unsigned char i;
- unsigned char dat;
-
- for(i=0;i<8;i++)
- {
- DQ = 0;
- dat >>= 1;
- DQ = 1;
- if(DQ)
- {
- dat |= 0x80;//从高位到低位一位一位写
- }
- Delay_OneWire(5);
- }
- return dat;
- }
-
- //DS18B20初始化
- bit init_ds18b20(void)
- {
- bit initflag = 0;
-
- DQ = 1;
- Delay_OneWire(12);
- DQ = 0;
- Delay_OneWire(80);
- DQ = 1;
- Delay_OneWire(10);
- initflag = DQ; //0表示初始化成功
- Delay_OneWire(5);
-
- return initflag;
- }

ds18b20.c需要我们写的函数:
- /*DS18B20温度读取函数*/
- float read_t()
- {
- unsigned char low,high;//返回温度数据的高低八位
-
- init_ds18b20();//初始化
- Write_DS18B20(0xcc);//跳过ROM
- Write_DS18B20(0x44);//进行温度转换
-
- init_ds18b20();//初始化
- Write_DS18B20(0xcc);//跳过ROM
- Write_DS18B20(0xbe);//读取温度
-
- low = Read_DS18B20();//读取低位
- high = Read_DS18B20();//读取高位
- return ((high << 8) | low) / 16.0;
- }

主函数处理:
- #include "onewire.h"
- ...
- ...
- ...
- float t;
- ...
- ...
- ...
- void Seg_Proc()
- {
- if(Seg_Slow_Down) return;
- Seg_Slow_Down = 1;//数码管减速程序
-
- t = read_t();//获取温度
-
- Seg_Buf[0] = (unsigned char)t / 10 % 10;//显示读取温度的十位
- Seg_Buf[1] = (unsigned char)t % 10;//显示读取温度的个位
- Seg_Buf[2] = (unsigned int)(t * 10) % 10;//显示读取温度的小数第一位
- }
- ...
- ...
- ...
- void main()
- {
- read_t();//上电读取温度,防止显示“85”
- Delay750ms();
- System_Init();
- Timer0Init();
- while (1)
- {
- Key_Proc();
- Seg_Proc();
- Led_Proc();
- }
- }

不同IC双向通信,串行数据线(SDA)和串行时钟线(SCL)外接上拉电阻。
底层代码:
- #include "iic.h"
-
- //总线引脚定义
- sbit SDA = P2^1; /* 数据线 */
- sbit SCL = P2^0; /* 时钟线 */
-
- void IIC_Delay(unsigned char i)
- {
- do{_nop_();}
- while(i--);
- }
-
- //总线启动条件
- void IIC_Start(void)
- {
- SDA = 1;
- SCL = 1;
- IIC_Delay(DELAY_TIME);
- SDA = 0;
- IIC_Delay(DELAY_TIME);
- SCL = 0;
- }
-
- //总线停止条件
- void IIC_Stop(void)
- {
- SDA = 0;
- SCL = 1;
- IIC_Delay(DELAY_TIME);
- SDA = 1;
- IIC_Delay(DELAY_TIME);
- }
-
- //发送应答
- void IIC_SendAck(bit ackbit)
- {
- SCL = 0;
- SDA = ackbit; // 0:应答,1:非应答
- IIC_Delay(DELAY_TIME);
- SCL = 1;
- IIC_Delay(DELAY_TIME);
- SCL = 0;
- SDA = 1;
- IIC_Delay(DELAY_TIME);
- }
-
- //等待应答
- bit IIC_WaitAck(void)
- {
- bit ackbit;
-
- SCL = 1;
- IIC_Delay(DELAY_TIME);
- ackbit = SDA;
- SCL = 0;
- IIC_Delay(DELAY_TIME);
- return ackbit;
- }
-
- //通过I2C总线发送数据
- void IIC_SendByte(unsigned char byt)
- {
- unsigned char i;
-
- for(i=0; i<8; i++)
- {
- SCL = 0;
- IIC_Delay(DELAY_TIME);
- if(byt & 0x80) SDA = 1;
- else SDA = 0;
- IIC_Delay(DELAY_TIME);
- SCL = 1;
- byt <<= 1;//从高位到低位,一位一位左移
- IIC_Delay(DELAY_TIME);
- }
- SCL = 0;
- }
-
- //从I2C总线上接收数据
- unsigned char IIC_RecByte(void)
- {
- unsigned char i, da;
- for(i=0; i<8; i++)
- {
- SCL = 1;
- IIC_Delay(DELAY_TIME);
- da <<= 1;
- if(SDA) da |= 1;从低位到高位一位一位左移
- SCL = 0;
- IIC_Delay(DELAY_TIME);
- }
- return da;
- }

在起始信号和结束信号中,SCL始终为高电平SDA跳变。所以在数据位传输期间当数据交换时需要把SCL拉低,否则当SCL=1,SDA的任何跳变都会被认为是总线信号的起始和暂停。
我们仅关注:地址线A0、A1、A2接地;ADC输入引脚AIN0、AIN1、AIN2、AIN3(AIN1接光敏电阻,AIN3接滑动变阻器);IIC通信引脚SCL、SDA。
地址:A2、A1、A0=0,读地址为0x91,写地址为0x90.
控制字:D1、D0为AD通道,00通道1、01通道1、10通道2、11通道3;D5、D4为模拟量输入选择:一般选择00(四路单输入);D2自动增益默认1;D6模拟输出允许默认1.
光敏电阻为0x41,滑动变阻器为0x43
IIC.c中需要我们写的AD、DA函数
- //函数名:ADC转换函数
- //入口参数:要进行转换的通道控制位
- //返回值:ADC转换的数值
- //函数功能:对指定的通道进行ADC转换,函数返回转换的数值
- unsigned char AD_Read(unsigned char channel_num_contrl)
- {
- unsigned char temp;
- /*读*/
- IIC_Start();//发送开启信号
- IIC_SendByte(0x90);//选择PCF8591芯片,确定写的模式
- IIC_WaitAck();//等待PCF8591反馈
-
- IIC_SendByte(channel_num_contrl);//确定要转换的通道(顺便,使能DA转换)
- IIC_WaitAck();//等待PCF8591反馈
- /*写*/
- IIC_Start();//发送开启信号
- IIC_SendByte(0x91);//选择PCF8591芯片,确定读的模式
- IIC_WaitAck();//等待PCF8591反馈
-
- temp = IIC_RecByte();//接收数据
- IIC_SendAck(1);//选择不应答
- IIC_Stop();//停止发送
-
- return temp;
-
- }
-
-
-
- //函数名:DAC转换函数
- //入口参数:要进行转换的数值
- //返回值:无
- //函数功能:对入口参数要转换的DA数据进行转换
- void DA_Write(unsigned char trans_dat)
- {
- IIC_Start();//发送开启信号
- IIC_SendByte(0x90);//选择PCF8591芯片,确定写的模式
- IIC_WaitAck();//等待PCF8591反馈
-
- IIC_SendByte(0x41);//使能DA转换(随便写通道编号,保证控制字D6为1即可,主要的功能是使能DA)
- IIC_WaitAck();//等待PCF8591反馈
-
- IIC_SendByte(trans_dat);//将待转换的数据发送出去
- IIC_WaitAck();//等待PCF8591反馈
- IIC_Stop();//停止发送
-
- }

主函数的处理:
- #include <iic.h>//数模转换底层驱动专属头文件
- ...
- ...
- ...
- float Voltage;//实时读取电压值,AD
- ...
- ...
- ...
- void Seg_Proc()
- {
-
- if(Seg_Slow_Down) return;
- Seg_Slow_Down = 1;//数码管减速程序
-
- /* 数据读取区域 */
- Voltage = AD_Read(0x43) / 51.0;//读取实时电压值
- DA_Write(127);//实时输出电压值
-
- /* 信息显示区域 */
- //AD读取值,数码管显示x.xx
- Seg_Buf[0] = (unsigned char)Voltage;
- Seg_Buf[1] = (unsigned int)(Voltage * 100) / 10 % 10;
- Seg_Buf[2] = (unsigned int)(Voltage * 100) % 10;
-
- }

若AD1读取光敏电阻(0x41)的值,AD2读取滑动变阻器(0x43)的值,在main.c中不写
AD1=Ad_Read(0x41);AD2=Ad_Read(0x43);
而是写:AD1=Ad_Read(0x43);AD2=Ad_Read(0x41);
硬件连接我们仅关注:地址线E0、E1、E2均为0,写保护WE=0,IIC通信线SCL、SDA。
设备地址字:该EERROM存储空间为2K,A2=A1=A0=0。读地址为0xA1,写地址为0xA0。
需要在iic.c写的EEPROM的函数:
- //函数名:写EEPROM函数
- //入口参数:需要写入的字符串,写入的地址(务必为8的倍数),写入数量
- //返回值:无
- //函数功能:向EERPOM的某个地址写入字符串中特定数量的字符。
- void EEPROM_Write(unsigned char* EEPROM_String, unsigned char addr, unsigned char num)
- {
- IIC_Start();//发送开启信号
- IIC_SendByte(0xA0);//选择EEPROM芯片,确定写的模式
- IIC_WaitAck();//等待EEPROM反馈
-
- IIC_SendByte(addr);//写入要存储的数据地址
- IIC_WaitAck();//等待EEPROM反馈
-
- while(num--)
- {
- IIC_SendByte(*EEPROM_String++);//将要写入的信息写入
- IIC_WaitAck();//等待EEPROM反馈
- IIC_Delay(200);
- }
- IIC_Stop();//停止发送
- }
-
-
- //函数名:读EEPROM函数
- //入口参数:读到的数据需要存储的字符串,读取的地址(务必为8的倍数),读取的数量
- //返回值:无
- //函数功能:读取EERPOM的某个地址中的数据,并存放在字符串数组中。
- void EEPROM_Read(unsigned char* EEPROM_String, unsigned char addr, unsigned char num)
- {
- IIC_Start();//发送开启信号
- IIC_SendByte(0xA0);//选择EEPROM芯片,确定写的模式
- IIC_WaitAck();//等待EEPROM反馈
-
- IIC_SendByte(addr);//写入要读取的数据地址
- IIC_WaitAck();//等待EEPROM反馈
-
- IIC_Start();//发送开启信号
- IIC_SendByte(0xA1);//选择EEPROM芯片,确定读的模式
- IIC_WaitAck();//等待EEPROM反馈
-
- while(num--)
- {
- *EEPROM_String++ = IIC_RecByte();//将要写入的信息写入
- if(num) IIC_SendAck(0);//发送应答
- else IIC_SendAck(1);//不应答
- }
-
- IIC_Stop();//停止发送
- }

主函数的处理:
- #include "iic.h"
- ...
- ...
- ...
- unsigned char dat[2] = {30,60};
- unsigned char a = 200;
- ...
- ...
- ...
- /* 键盘处理函数 */
- void Key_Proc()
- {
- if(Key_Slow_Down) return;
- Key_Slow_Down = 1;//键盘减速程序
-
- Key_Val = Key_Read();//实时读取键码值
- Key_Down = Key_Val & (Key_Old ^ Key_Val);//捕捉按键下降沿
- Key_Up = ~Key_Val & (Key_Old ^ Key_Val);//捕捉按键上降沿
- Key_Old = Key_Val;//辅助扫描变量
-
- switch(Key_Down)
- {
- case 19:
- a += 10;
- break;
- case 18:
- dat[1] -= 10;
- break;
- case 17:
- EEPROM_Write(dat,0,2);
- break;
- case 16:
- EEPROM_Write(&a,0,1);
- break;
- }
-
- }
- ...
- ...
- ...
-
- /* 信息处理函数 */
- void Seg_Proc()
- {
- if(Seg_Slow_Down) return;
- Seg_Slow_Down = 1;//数码管减速程序
-
- Seg_Buf[0] = a / 100 % 10;
- Seg_Buf[1] = a / 10 % 10;
- Seg_Buf[2] = a % 10;
-
-
- Seg_Buf[6] = dat[1] / 10;
- Seg_Buf[7] = dat[1] % 10;
- }
- ...
- ...
- ...
- void main()
- {
- EEPROM_Read(&a,0,1);
- EEPROM_Read(dat,0,2);
- System_Init();
- Timer0Init();
- while (1)
- {
- Key_Proc();
- Seg_Proc();
- Led_Proc();
- }
- }

第一次烧录前将主函数的读出函数删除(注释),烧录后修改变量的值并保存到EEPROM中。断电,将主函数的读出函数加上,上电后显示的变量为修改后的变量。
由于EEPROM读写数据以字节为单位,所以在使用中尽量使用char型。
由原理图可知,NE555的输出引脚OUT连接NET SIG,当使用跳线帽连接P34引脚后,使用定时器1作为定时器(中断号为3)进行1ms定时,使用定时器0作为计数器记录脉冲上升沿。
在TIM0的TMOD中,GATE配置为0,C/T配置为1,M1、M0配置为01模式,即16位不可重装载模式。TMOD0=0101.
使用STC—ISP对定时器0进行如下配置
不需要进行定时器0中断修改代码为(将TMOD |= 0x01;修改为TMOD |= 0x05;)
- void Timer0Init(void) //1毫秒@12.000MHz
- {
- AUXR &= 0x7F; //定时器时钟12T模式
- TMOD &= 0xF0; //设置定时器模式
- TMOD |= 0x05; //设置计数模式
- TL0 = 0; //设置定时初始值
- TH0 = 0; //设置定时初始值
- TF0 = 0; //清除TF0标志
- TR0 = 1; //定时器0开始计时
- }
-
- void Timer1Init(void) //1毫秒@12.000MHz
- {
- AUXR &= 0xBF; //定时器时钟12T模式
- TMOD &= 0x0F; //设置定时器模式
- TL1 = 0x18; //设置定时初值
- TH1 = 0xFC; //设置定时初值
- TF1 = 0; //清除TF1标志
- TR1 = 1; //定时器1开始计时
- ET1 = 1;
- EA = 1;
- }

注意:(1)频率值定义为int型(必超255)(2)定时器中断号为3 (3)TH0、TL0的值需要手动归零
- unsigned int Timer_1000Ms;//1000毫秒计时变量
- unsigned int Freq;//实时频率值
-
- void Timer1Server() interrupt 3
- {
- if(++Key_Slow_Down == 10) Key_Slow_Down = 0;//键盘减速专用
- if(++Seg_Slow_Down == 500) Seg_Slow_Down = 0;//数码管减速专用
- if(++Seg_Pos == 8) Seg_Pos = 0;//数码管显示专用
- Seg_Disp(Seg_Pos,Seg_Buf[Seg_Pos],Seg_Point[Seg_Pos]);
- Led_Disp(Seg_Pos,ucLed[Seg_Pos]);
-
-
- if(++Timer_1000Ms == 1000) //实时读取频率值
- {
- Timer_1000Ms = 0;
- Freq = TH0 << 8 | TL0;
- TH0 = TL0 = 0;
- }
- }

一般要求设置20%这样的占空比,可考虑在定时器中断中使一个count变量从0到9往复循环,定义一个阈值例如2,可以在一个周期内进行两个变量的比较,例如低于阈值输出1高于阈值输出0,以此在极短的时间内从宏观上控制功率。
下面以P34引脚输出不同占空比、频率为1kHz的PWM为例:
由于频率为1kHz(要实现定时器里的count变量从0到9,定时器的周期要0.1ms)而定时器0的周期为1ms,所以需要重新使能另一个定时器。
- void Timer1Init(void) //100微秒@12.000MHz
- {
- AUXR &= 0xBF; //定时器时钟12T模式
- TMOD &= 0x0F; //设置定时器模式
- TL1 = 0x9C; //设置定时初值
- TH1 = 0xFF; //设置定时初值
- TF1 = 0; //清除TF1标志
- TR1 = 1; //定时器1开始计时
- ET1 = 1;
- }
-
- void Timer1Server() interrupt 3
- {
- if(work_time != 0)
- {
- if(++pwm_count == 10) pwm_count = 0;
- switch(wind_mode)
- {
- case 0:
- pwm_level = 2;
- break;
- case 1:
- pwm_level = 3;
- break;
- case 2:
- pwm_level = 7;
- break;
- }
- if(pwm_count >= pwm_level) P34 = 0;
- else P34 = 1;
- }
- }

使能定时器1 中断,每0.1ms进入一次中断实现pwm_count++,根据pwm_count和pwm_level的大小关系,给P34电平的高和低。
J2跳线帽选1-3 3-5,一般选用定时器1作为信号测量。发送引脚TX,接受引脚RX。
- #include <ultrasonic.h>
- #include <intrins.h>
-
- sbit Tx = P1^0;
- sbit Rx = P1^1;
-
- void Delay12us() //@12.000MHz
- {
- unsigned char i;
-
- _nop_();
- _nop_();
- i = 38;
- while (--i);
- }
-
-
- void Wave_Init()
- {
- unsigned char i;
- for(i=0;i<8;i++)
- {
- Tx = 1;
- Delay12us();
- Tx = 0;
- Delay12us();
- }
- }
-
- unsigned int Ut_Wave_Data() //超声波距离读取函数
- {
- unsigned int time;//时间储存变量
- CMOD = 0x00;//配置PCA工作模式
- CH = CL = 0;//复位计数值 等待超声波信号发出
- Wave_Init();//发送超声波信号
- CR = 1;//开始计时
- while((Rx == 1) && (CF == 0));//等待接受返回信号或者定时器溢出
- CR = 0;//停止计时
- if(CF == 0) //定时器没有溢出
- {
- time = CH << 8 | CL;//读取当前时间
- return (time * 0.017);//返回距离值
- }
- else
- {
- CF = 0;//清除溢出标志位
- return 0;
- }
- }

初始化TX产生8个40KHz的方波信号,开启定时器计时,接收到超声波信号返回后关闭定时器。默认声速340m/s,距离=时间*0.017(cm)
main.c的使用
- unsigned char Wave_Data;
-
- void Seg_Proc()
- {
- if(Seg_Slow_Down) return;
- Seg_Slow_Down = 1;//数码管减速程序
-
- Wave_Data = Ut_Wave_Data();
-
- Seg_Buf[0] = Wave_Data / 100 % 10;
- Seg_Buf[1] = Wave_Data / 10 % 10;
- Seg_Buf[2] = Wave_Data % 10;
- }
配置如下:
添加“ES=1;EA=1”
uart.c如下:
- #include <Uart.h>
-
- /* 串口初始化函数 */
- void UartInit(void) //9600bps@12.000MHz
- {
- SCON = 0x50; //8位数据,可变波特率
- AUXR |= 0x01; //串口1选择定时器2为波特率发生器
- AUXR |= 0x04; //定时器时钟1T模式
- T2L = 0xC7; //设置定时初始值
- T2H = 0xFE; //设置定时初始值
- AUXR |= 0x10; //定时器2开始计时
- ES = 1;
- EA = 1;
- }
-
- /* 字节发送函数 */
- void SendByte(unsigned char dat)
- {
- SBUF=dat;//将dat数据赋给SBUF,将数据发送出去
- while(TI == 0);//等待数据发送
- TI = 0;//将发送标志位清零
- }
-
- /* 字符串发送函数 */
- void Uart_Send_String(unsigned char *dat)
- {
- while(*dat != '\0')//当字符不为空时,继续发送
- SendByte(*dat++);//发送后指针dat加1,指向下一个字节
- }

由于定时器0负责三大模块的扫描与其他变量的计数,定时器1负责超声波或NE555的计数,故使用定时器2作为波特率发生器。
main.c处理:
- #include <Uart.h>//串口底层驱动专用头文件
- #include <stdio.h>
-
-
- unsigned char Uart_Slow_Down;//串口减速专用变量
- unsigned char Uart_Recv[10];//串口接收数据储存数组 默认10个字节 若接收数据较长 可更改最大字节数
- unsigned char Uart_Recv_Index;//串口接收数组指针
- unsigned char Uart_Send[10];//串口接收数据储存数组 默认10个字节 若发送数据较长 可更改最大字节数
- unsigned char dat;
-
- void Key_Proc()
- {
- if(Key_Slow_Down) return;
- Key_Slow_Down = 1;//键盘减速程序
-
- Key_Val = Key_Read();//实时读取键码值
- Key_Down = Key_Val & (Key_Old ^ Key_Val);//捕捉按键下降沿
- Key_Up = ~Key_Val & (Key_Old ^ Key_Val);//捕捉按键上降沿
- Key_Old = Key_Val;//辅助扫描变量
-
- switch(Key_Down)
- {
- case 4:
- sprintf(Uart_Send,"T = %.2f\r\n",t);
- Uart_Send_String(Uart_Send);
- break;
- }
- }
-
- void Seg_Proc()
- {
- if(Seg_Slow_Down) return;
- Seg_Slow_Down = 1;//数码管减速程序
-
- t = rd_temperature();
-
- Seg_Buf[0] = dat / 10;
- Seg_Buf[1] = dat % 10;
- }
-
-
- void Uart_Proc()
- {
- if(Uart_Slow_Down) return;
- Uart_Slow_Down = 1;//串口减速程序
-
- if(Uart_Recv_Index == 6)
- {
- if(Uart_Recv[0] == 'L' && Uart_Recv[1] == 'e' && Uart_Recv[2] == 'd' && Uart_Recv[4] == '=')
- ucLed[Uart_Recv[3] - 48] = Uart_Recv[5] - 48;
- Uart_Recv_Index = 0;
- }
- }
-
-
- void Uart1Server() interrupt 4
- {
- if(RI == 1) //串口接收数据
- {
- Uart_Recv[Uart_Recv_Index] = SBUF;
- Uart_Recv_Index++;
- RI = 0;
- }
- }
-
-
- void main()
- {
- System_Init();
- Timer0Init();
- UartInit();
- while (1)
- {
- Key_Proc();
- Seg_Proc();
- Led_Proc();
- Uart_Proc();
- }
- }

按下S4向串口发送一次温度数据,在接受缓冲区显示。在发送缓冲区输入“Ledi=x”可改变LED状态。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。