赞
踩
对蓝桥杯单片机类知识点的一次抱佛脚总结 :(
目录
(1)简单读取出温度
- #include "onewire.h"
- float temp=0; //定义一个温度变量
- void Read_Temp()
- {
- uchar LSB,MSB; //定义出低八位和高八位接收变量
- init_ds18b20();//初始化DS18B20
- Write_DS18B20(0xcc); //跳过RAM
- Write_DS18B20(0x44); //开始温度转换
-
- Delay_Display(500); //延时等待应答,同时不影响数码管和LED灯的显示
-
- init_ds18b20();//重新初始化DS18B20
- Write_DS18B20(0xcc); //跳过RAM
- Write_DS18B20(0xbe); //读取温度
-
- LSB=Read_DS18B20(); //先读低八位
- MSB=Read_DS18B20(); //再读高八位
- temp=(MSB<<8)|LSB; //合并高低位
-
- if(temp&0xf800==0x0000) //判断temp是否大于0(高五位为符号位)
- temp==temp>>4; //低四位为小数位,若要读出整数,则直接将低四位丢弃
- else
- temp=(1-temp)>>4; //若温度小于0,先取反后移走小数位
- }

(2)温度保留小数
若题目要求保留*位小数(以两位小数为例):
- temp=temp>>4; //先将小数位移走
- temp=temp*100; //将整数部分放大一百倍(利于后续显示)
- temp=temp+((LSB&0x0f)*0.0625)*100; //取出低四位(小数位),乘以精度(0.0625),再放大100倍
-
- //或直接:
- temp=temp*0.0625*100;
(1)将时间写入芯片
通常是将初始化时间写入其中(放在主函数while之前):
- #include "ds1302.h"
- uchar DS1302_WriteAddress[7]={0x80,0x82,0x84,0x86,0x88,0x8a,0x8c}; //写地址
- uchar Time[7]={0x59,0x59,0x23,0x04,0x04,0x02,0x23}; //初始化时间2023/4/4 23:59:59 星期二
- void Write_DS1302()
- {
- uchar i;
- Write_Ds1302_Byte(0x8e,0x00); //打开写保护
- for(i=0;i<7;i++)
- Write_Ds1302_Byte(DS1302_WriteAddress[i],Time[i]); //将每一位写入
- Write_Ds1302_Byte(0x8e,0x80); //关闭写保护
- }
(2)从芯片中读时间
- #include "ds1302.h"
- uchar Read_DS1302Address[7]={0x81,0x83,0x85,0x87,0x89,0x8b,0x8d};
- void Read_DS1302()
- {
- uchar i;
- for(i=0;i<7;i++)
- Time[i]=Read_Ds1302_Byte(Read_DS1302Address[i]);
- }
时间和温度传感器比较基础简单,一些记不住的指令、地址格式,要学会查找芯片手册,很容易就能找到。
可用来定时、计数。可用定时计数器实现的模块有PWM脉宽调制、NE555、超声波测距、串口调制......
通常可以用烧录软件直接生成定时器初始化代码,选择12T,然后再将总中断和定时器中断打开即可。
演示定时器0,16位定时器,定时100us:
- void Timer0Init(void) //100微秒@12.000MHz
- {
- AUXR &= 0x7F; //定时器时钟12T模式
- TMOD &= 0xF0; //设置定时器模式
- TMOD |= 0x01; //设置定时器模式
- TL0 = 0x9C; //设置定时初始值
- TH0 = 0xFF; //设置定时初始值
- TF0 = 0; //清除TF0标志
- TR0 = 1; //定时器0开始计时
- //以上均为软件直接生成
- EA=1; //打开总中断
- ET0=1; //打开定时器0中断
- }
用户手册的查询很重要!!!
常用参数:
·pwm_count:计数(以达到占空比和总频率数量)
·pwm_duty:占空比(对应的数值)
·pwm_flag:当前PWM控制的外设的状态(通常为0灭/关 1亮/开)
- //假设信号频率为1KHZ
- //则 f=1000hz T=1ms=1000us=100*10
- uint pwm_count=0; //pwm占空(或占高电平)的计数值
- uint pwm_duty=30; //pwm规定占空比的值
- bit pwm_flag=0; //pwm控制的外设的当前状态位
-
- void InitTimer0() //定时100us
- {
- TMOD=0x01;
-
- TH0=(65535-100)/256;
- TL0=(65535-100)%256;
-
- TR0=1;
- ET0=1;
- EA=1;
- }
-
- void Service_Timer0() //在定时器0的中断服务函数中进行脉宽调制
- {
- TH0=(65535-100)/256;
- TL0=(65535-100)%256;
-
- //PWM脉宽调制
- pwm_count++;
- if(pwm_count>=pwm_duty) //占空比设定
- pwm_flag=1;
- if(pwm_count>=10) //整个周期
- {
- pwm_count=0;
- pwm_flag=0;
- }
- }

频率即为1s中信号发生的次数。测量频率可用Timer0做计数器,初值调到最大,这样来一个脉冲产生一次定时器中断。Timer1做定时器,定时1s。
- uint f_count=0; //脉冲计数
- uint f_number=0;//频率值
- uint count=0; //定时器计数
- //1s = 1000ms = 1000000us = 50000 * 20
- void InitTimer() //Timer0和Timer1初始化
- {
- TMOD=0x16; //0001 0110
-
- TH0=0xff;
- TL0=0xff;
- TH1=(65535-50000)/256;
- TL1=(65535-50000)%256;
-
- EA=1;
- ET0=1;
- ET1=1;
-
- TR0=1;
- TR1=1;
- }
-
- void Service_Timer0() interrupt 1
- {
- f_count++;
- }
-
- void Service_Timer1() interrupt 2
- {
- TH1=(65535-50000)/256;
- TL1=(65535-50000)%256;
-
- count++;
- if(count>=20) //计时到一秒后
- {
- f_number=f_count; //记录下当前的频率计数值作为频率值
- f_count=0;
- count=0;
- }
- }
-
-

通常用到的电阻为通道1的光敏电阻和通道3的滑阻(rb2),同时需要注意AD转换周期总是在发送一个有效的读模式地址到PCF8591设备后开始,即本次显示的电压是上次采集到的电压。
以通道3的rb2(光敏电阻)为例:
(1)AD转换(读取电压)
- #include "iic.h"
- uint rb2=0; //用于存放读取的rb2的值
- void Ad_Read()
- {
- IIC_Start(); //iic开始信号
- IIC_SendByte(0x90); //写控制字
- IIC_WaitAck(); //等待应答
- IIC_SendByte(0x43);//将要读的地址写入
- IIC_WaitAck();
-
- IIC_Start(); //iic开始信号
- IIC_SendByte(0x91); //读控制字
- IIC_WaitAck(); //等待应答
- rb2=IIC_RecByte(); //读取电压值
- IIC_SendAck(1); //发送应答,表明可以结束了
- IIC_Stop(); //总线停止
- }

读取出的是 数字量 ,即若此时直接用数码管显示,显示出的值为0~255
若要显示出读到的模拟量,直接用rb2/51.0即可
(2)DA转换
- void Da_Write(uint dat) //此处dat为数字量(0~255)
- {
- IIC_Start();
- IIC_SendByte(0x90); //发送写控制字
- IIC_WaitAck();
- IIC_SendByte(0x43); //发送写入的地址
- IIC_WaitAck();
- IIC_SendByte(dat); //写入DAC的值
- IIC_WaitAck();
- IIC_Stop();
- }
直接调用 如:Da_Write(127); 则通道三输出模拟量即为127/51
EEPROM掉电不丢失,常用于保存数据。在下次上电瞬间读出(即将读操作放在while(1)循环之前)。与PCF8591同样使用iic协议,故读写步骤基本相同。
(1)读操作
- uint Read_AT24C02(uchar addr)
- {
- uint temp=0;
- //从地址addr中读出数据,此处addr可自己定义,通常从0x00开始
- IIC_Start();
- IIC_SendByte(0xa0); //发送写控制字
- IIC_WaitAck();
- IIC_SendByte(addr); //将地址写入
- IIC_WaitAck();
- IIC_SendByte(0xa1); //发送读控制字
- IIC_WaitAck();
- temp=IIC_RecByte(); //读取数据
- IIC_SendAck(1); //发送结束应答
- IIC_Stop(); //总线停止
- return temp;
- }

(2)写操作
- void Write_AT2402(uchar addr,uchar dat)
- {
- IIC_Start();
- IIC_SendByte(0x90); //写控制字
- IIC_WaitAck();
- IIC_SendByte(addr); //写入地址
- IIC_WaitAck();
- IIC_SendByte(dat); //写入数据
- IIC_WaitAck();
- IIC_Stop();
- }
Tx为发射信号一端,地址为P1^0;Rx为接收信号的一端,地址为P1^1
Tx=1时成功发送信号,Tx=0时发送失败;
Rx=0时成功接收信号,Rx=1时接收失败。
- sbit Tx=P1^0;
- sbit Rx=P1^1;
- void Wave_Init() //超声波初始化函数,实际上就是发射8个40khz的超声波信号
- {
- uchar i;
- for(i=0;i<8;i++)
- {
- Tx=1;
- //f=40khz,T=1/f=25us,方波占空比为50%,即延时12.5us
- Delay12us();
- Tx=0;
- Delay12us();
- }
- }
-
- uchar Wave_Data() //超声波距离读取函数
- {
- uint time=0; //时间储存变量
- TMOD&=0x0f //T1计数模式、十六位自动重装,T0设置不变
- TH1=TL1=0;
- Wave_Init(); //发送超声波信号
- TR1=1; //开始计时
- while((Rx==1)&&(TF1==0)); //等待接收信号,同时计数器没有溢出
- TR1=0; //停止计时
- if(TF1==0) //计数器1没有溢出
- {
- time=(TH1<<8)|TL1;
- // return (time*(340/2)*0.000001*100); //cm为单位
- return (time*0.017); //直接这样写!否则会出错!
- }
- else
- {
- TF1=0; //清除溢出标志位
- return 0;
- }
- }

串行通信。SCON串行控制器,一般使用01方式1,8位UART,波特率可变(波特率类似于传输速度)。
串行口1缓冲寄存器(SBUF)的地址是99H,实际是两个缓冲器,一个是发送寄存器,一个是接收寄存器,物理结构上完全独立,字节地址均为99H,是通过读/写指令来区分的。
串行发送时:CPU向SBUF写入数据,此时99H表示发送缓存SBUF
串行接收时:CPU向SBUF读取数据,此时99H表示接收缓存SBUF
数据发送:数据丢进SBUF,内核自动发送,发送完毕,TI标志位置1;
数据接收:内核从串口接收到一个完整数据后,RI置1,用户用SBUF读取。
IE中有EA=1;(总中断打开)ES=1;(串口中断打开)
串口设计使用一般要写三个函数:串口初始化函数、字节发送函数、串口中断服务函数(接收数据,使用中断)。
(1)串口初始化函数
- //STC软件--系统频率12--串口1--波特率(默认)9600--8位数据--定时器2--定时器时钟12T
- void UartInit(void) //9600bps@12.000MHz
- {
- SCON = 0x50; //8位数据,可变波特率
- AUXR |= 0x01; //串口1选择定时器2为波特率发生器
- AUXR &= 0xFB; //定时器时钟12T模式
- T2L = 0xE6; //设置定时初始值
- T2H = 0xFF; //设置定时初始值
- AUXR |= 0x10; //定时器2开始计时
-
- //加入:
- EA=1;
- ES=1;
- }
(2)字节发送函数
- void SendByte(unsigned char dat)
- {
- SBUF=dat; //将dat赋给SBUF,将数据发送出去
- while(TI==0); //等待数据发送
- TI=0; //发送标志位清0
- }
(3)字符串发送函数
- void Uart_Send_String(uchar *dat)
- {
- while(*dat!='\0')
- SendByte(*dat++);
- }
(4)串口接收数据(串口1中断服务函数)
- uchar Uart_Recv[10]; //串口接收数据存储数组
- uchar Uart_Send[10]; //串口发送数据存储数组
- uchar Uart_Recv_Index=0; //串口接收数组指针
-
- void Uart1Server() interrupt 4
- {
- if(RI==1) //串口接收到数据
- {
- Uart_Recv[Uart_Recv_Index]=SBUF;
- Uart_Recv_Index++;
- RI=0;
- }
- }
串口助手:选择文本模式--串口选择USB所在串口--波特率9600--编程完自动打开串口
(5)比赛中发送数据
- //假设单片机要发送 温度=23.36 类似格式到pc:
- //使用字符串格式化函数 sprintf
-
- #include "stdio.h"
- //通常用在按键里,如按下S9发送:
- void ScanKeys()
- {
- if(Ket_Down==9)
- {
- sprintf(Uart_Send,"温度 = %.2f\r\n",t); //格式化字符串
- Uart_SendString(Uart_Send); //发送
- }
- }
(6)比赛中发送指令让单片机做对应操作
- //1.发送区发送数字,数码管显示该数字
- uchar dat;
- void Uart_Proc()
- {
- if(Uart_Recv_Index==1)
- {
- dat=Uart_Recv[0]-48; //ASCII码-48
- Uart_Recv_Index=0; //复位为0
- }
- //后面再将dat直接显示到数码管即可
- }
- //2.发LED0=0,则让LED0熄灭。。。
- //LED_=_ 一共六位
- void Uart_Proc()
- {
- if(Uart_Recv_Index==6) //直接先判断是不是六位
- {
- if(Uart_Recv[0]=='L'&&Uart_Recv[1]=='E'&&Uart_Recv[2]=='D'&&Uart_Recv[4]=='=')
- {
- SelectHC573(4);
- ucLED[Uart_Recv[3]-48] = Uart_Recv[5] - 48;
- Uart_Recv_Index = 0;
- }
- }
- }
(1)iic:
(2)onewire:
再加上.h文件即可
(3)ds1302:
引脚定义均可在原理图上找到。
- #include "reg52.h"
- #include "onewire.h"
- #include "iic.h"
- #include "stdio.h"
- typedef unsigned int uint;
- typedef unsigned char uchar;
-
- sfr AUXR=0x8e;
- sfr T2L=0xd7;
- sfr T2H=0xd6;
- sfr P4=0xc0;
- sbit C1=P4^4;
- sbit C3=P3^5;
- sbit R3=P3^2;
- sbit R4=P3^3;
-
- sbit L1=P0^0;
- sbit L2=P0^1;
- sbit L3=P0^2;
- sbit buzzer=P0^6;
- sbit relay=P0^4;
-
- uchar SMG_NoDot[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
- uchar SMG_Dot[10]={0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10};
-
- uchar lock=0; //按键S4标志位 0:解锁,1:锁死
- uchar uart_flag=0; //串口发送标志位
- uint temp=0; //读取温度数值
- uint ad_v=0; //电压读取
- uint count=0; //闪烁计数
- uchar Data=0; //串口接收数据
- uchar Uart_Send[20];//串口发送数组
- uchar mode=0; //显示界面模式 0:温度数据 1:电压数据
- bit L3_flag=0; //L3闪烁标志位
-
- void Delay_Display(uint t);
- void LedRunning();
- void Relay_Buzzer();
-
- //=====================系统初始化======================
- void Delay(uint t)
- {
- while(t--);
- }
-
- void SelectHC573(uchar channel)
- {
- switch(channel)
- {
- case 4:
- P2=(P2&0x1f)|0x80;break;
- case 5:
- P2=(P2&0x1f)|0xa0;break;
- case 6:
- P2=(P2&0x1f)|0xc0;break;
- case 7:
- P2=(P2&0x1f)|0xe0;break;
- case 0:
- P2=(P2&0x1f)|0x00;break;
- }
- }
-
- void InitSystem()
- {
- SelectHC573(4);
- P0=0xff;
- SelectHC573(5);
- P0=0x00;
- SelectHC573(0);
- }
- //=====================================================
-
- //=======================温度读取=======================
- void Read_Temp()
- {
- uchar LSB,MSB;
- init_ds18b20();
- Write_DS18B20(0xcc);
- Write_DS18B20(0x44);
-
- Delay_Display(100);
-
- init_ds18b20();
- Write_DS18B20(0xcc);
- Write_DS18B20(0xbe);
- LSB=Read_DS18B20();
- MSB=Read_DS18B20();
- temp=(MSB<<8)|LSB;
-
- if((temp&0xf800)==0x0000) //若温度大于0
- {
- temp=(temp>>4)*10;
- temp=temp+(LSB&0x0f)*0.0625*10;
- }
- }
- //======================================================
-
- //==================rb2(通道三)电压读取==================
- void Read_v()
- {
- uchar v;
- IIC_Start();
- IIC_SendByte(0x90); //发送写命令字
- IIC_WaitAck();
- IIC_SendByte(0x43); //写入要读的电压所在地址
- IIC_WaitAck();
-
- IIC_Start();
- IIC_SendByte(0x91); //发送读命令字
- IIC_WaitAck();
- v=IIC_RecByte();
- IIC_SendAck(1);
- IIC_Stop();
-
- ad_v=v*(5.0/255)*100;
- }
- //=======================================================
-
- //=====================定时器相关函数====================
- void Timer0Init(void) //10000微秒@12.000MHz
- {
- AUXR &= 0x7F; //定时器时钟12T模式
- TMOD &= 0xF0; //设置定时器模式
- TMOD |= 0x01; //设置定时器模式
- TL0 = 0xF0; //设置定时初始值
- TH0 = 0xD8; //设置定时初始值
- TF0 = 0; //清除TF0标志
- //TR0 = 1; //定时器0开始计时
-
- EA=1;
- ET0=1;
- }
-
- void Timer0_Server() interrupt 1
- {
- //0.1s=100ms=100000us = 10000*10
- TL0 = 0xF0; //设置定时初始值
- TH0 = 0xD8; //设置定时初始值
-
- if(lock==1)
- {
- count++;
- if(count>=10)
- {
- L3_flag=~L3_flag;
- count=0;
- }
- }
- }
- //========================================================
-
- //==================串口相关函数==========================
- void UartInit(void) //9600bps@12.000MHz
- {
- SCON = 0x50; //8位数据,可变波特率
- AUXR |= 0x01; //串口1选择定时器2为波特率发生器
- AUXR &= 0xFB; //定时器时钟12T模式
- T2L = 0xE6; //设置定时初始值
- T2H = 0xFF; //设置定时初始值
- AUXR |= 0x10; //定时器2开始计时
-
- EA=1;
- ES=1;
- }
-
- void SendByte(uchar dat) //发送字节
- {
- SBUF=dat;
- while(TI==0); //等待字节发送完毕
- TI=0;
- }
-
- void SendString(uchar *dat) //发送字符串
- {
- while(*dat!='\0')
- SendByte(*dat++);
- }
-
- void UART1() interrupt 4
- {
- if(RI)
- {
- Data=SBUF;
- if(lock==0) //未锁定状态下执行命令
- {
- if(Data=='A')
- mode=0;
- else if(Data=='B')
- mode=1;
- }
- RI=0;
- }
- }
-
- void Send_uart()
- {
- if(uart_flag==1)
- {
- if(mode==0)
- sprintf(Uart_Send,"TEMP:%.1f℃\r\n",(float)temp/10.0);
- else if(mode==1)
- sprintf(Uart_Send,"Voltage:%.2V\r\n",(float)ad_v/100);
- SendString(Uart_Send);
- uart_flag=0;
- }
- }
- //========================================================
-
- //====================数码管显示函数=======================
- void DisplaySMG_Bit(uchar pos,uchar dat)
- {
- SelectHC573(7);
- P0=0xff;
- SelectHC573(6);
- P0=0x01<<pos-1;
- SelectHC573(7);
- P0=dat;
- SelectHC573(0);
- }
-
- void DisplaySMG_All(uchar dat)
- {
- SelectHC573(6);
- P0=0xff;
- SelectHC573(7);
- P0=dat;
- SelectHC573(0);
- }
-
- void DisplaySMG()
- {
- if(mode==0)
- {
- DisplaySMG_Bit(1,0xc1);
- Delay(500);
- DisplaySMG_Bit(2,SMG_NoDot[1]);
- Delay(500);
-
- DisplaySMG_Bit(6,SMG_NoDot[temp/100]);
- Delay(500);
- DisplaySMG_Bit(7,SMG_Dot[(temp/10)%10]);
- Delay(500);
- DisplaySMG_Bit(8,SMG_NoDot[temp%10]);
- Delay(500);
-
- DisplaySMG_All(0xff);
- }
- else if(mode==1)
- {
- DisplaySMG_Bit(1,0xc1);
- Delay(500);
- DisplaySMG_Bit(2,SMG_NoDot[2]);
- Delay(500);
-
- DisplaySMG_Bit(6,SMG_Dot[ad_v/100]);
- Delay(500);
- DisplaySMG_Bit(7,SMG_NoDot[(ad_v/10)%10]);
- Delay(500);
- DisplaySMG_Bit(8,SMG_NoDot[ad_v%10]);
- Delay(500);
-
- DisplaySMG_All(0xff);
- }
- }
- //=========================================================
-
- //======================按键扫描函数========================
- void Show_down()
- {
- LedRunning();
- DisplaySMG();
- Relay_Buzzer();
- }
-
- void Delay_Display(uint t)
- {
- while(t--)
- {
- LedRunning();
- DisplaySMG();
- Relay_Buzzer();
- }
- }
-
- void ScanKeys()
- {
- C1=0;
- C3=1;
- R3=R4=1;
- if(R4==0) //按下S4
- {
- Delay(100);
- if(R4==0)
- {
- while(R4==0)
- Show_down();
- lock=1;
- }
- }
-
- C1=0;
- C3=1;
- R3=R4=1;
- if(R3==0) //按下S5
- {
- Delay(100);
- if(R3==0)
- {
- while(R3==0)
- Show_down();
- if(lock==1)
- lock=0;
- }
- }
-
- C1=1;
- C3=0;
- R3=R4=1;
- if(R4==0) //按下S12
- {
- Delay(100);
- if(R4==0)
- {
- while(R4==0)
- Show_down();
- uart_flag=1;
- }
- }
- }
- //=========================================================
-
- //=======================LED灯显示函数======================
- void LedRunning()
- {
- SelectHC573(4);
- P0=0xff;
- if(mode==0)
- L1=0;
- else
- L1=1;
-
- if(mode==1)
- L2=0;
- else
- L2=1;
-
- if(lock==1)
- {
- TR0=1;
- L3=L3_flag;
- }
- else
- {
- TR0=0;
- L3=1;
- }
- SelectHC573(0);
- }
- //=========================================================
-
- //=====================继电器与蜂鸣器======================
- void Relay_Buzzer()
- {
- SelectHC573(5);
- if(temp>=280)
- relay=1;
- else
- relay=0;
-
- if(ad_v>360)
- buzzer=1;
- else
- buzzer=0;
-
- SelectHC573(0);
- }
- //=========================================================
-
- void main()
- {
- InitSystem();
- Timer0Init();
- UartInit();
- while(1)
- {
- Read_v();
- Read_Temp();
- DisplaySMG();
- ScanKeys();
- Send_uart();
- LedRunning();
- }
- }

呜呜呜呜孩子紧张啊让孩子好好拿个奖吧呜呜呜呜呜呜呜声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。