楼主最近做到一个作业,要求用51单片机做一个风扇温控检测系统,其功能大概就是:当温度达到设定值时候,风扇电机开始转动,以达到散热的目的,题目本身没有什么意思,有意思的是想要用尽可能少的元器件来完成这项工作,要求使用两个数码管,其他没说,所以我就加了3个按键,大体思路是这样的,开机以后,正常显示温度,按下SET键位时候,进温度设置,两个按键+和-设置数值。再按一次SET保存并退出。
最有意思的在于用了两个标志位,这两个标志位简直没把我绕晕。现在完成了,发出来大家一起看看,不在于代码多好,在于一种解决问题的方法。我把文件发上来了,大家一起学习交流。
仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
单片机源程序如下:
- #include "reg52.h"
- #include <intrins.h>
- #define _Nop() _nop_() //定义空指令
- /*-----------------------------------------------
- IO口定义
- -----------------------------------------------*/
- sbit LED_R = P1^6; //红灯
- sbit BEEP = P2^1; //蜂鸣器
- sbit MOTOR = P2^2; //电机
- sbit KEY_ADD = P2^5; //加
- sbit KEY_DEC = P2^4; //减
- sbit KEY_SET = P2^3; //确认
- sbit ONE = P2^6; //个位位选
- sbit TEN = P2^7; //十位位选
- sbit DQ=P1^7; //DS18B20数据
- sbit SDA=P1^1; //模拟I2C数据传送位
- sbit SCL=P1^0; //模拟I2C时钟控制位
-
-
- /*-----------------------------------------------
- 定义变量
- -----------------------------------------------*/
- unsigned char Set_Flag=0; //
- unsigned char Set_Value=40; //设定值
- unsigned char Tempature = 0; //温度
- unsigned char num=40; //数字
- unsigned char table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f}; //数码管段选
- unsigned char Data=0;
- char Temp[12];
- bit ack; //应答标志位
- /*-----------------------------------------------
- 延时函数
- -----------------------------------------------*/
- void Delay_us(unsigned char t)
- {
- while(t--);
- }
- void Delay_ms(unsigned char t)
- {
- int i,j;
- for(i=t;i>0;i--)
- for(j=125;j>0;j--);
- }
- void delay_18B20(unsigned int i)//微秒级延时
- {
- while(i--);
- }
- /*-----------------------------------------------
- DS18B20初始化
- -----------------------------------------------*/
- void ds1820rst(void) /*ds1820复位*/
- {
- unsigned char x=0;
- DQ = 1; //DQ复位
- delay_18B20(5); //延时
- DQ = 0; //DQ拉低
- delay_18B20(100); //精确延时大于480us
- DQ = 1; //拉高
- delay_18B20(40);
- }
- unsigned char ds1820rd(void)//从18b20读取数据
- {
- unsigned char i=0;
- unsigned char dat = 0;
- for (i=8;i>0;i--)
- {
- DQ = 0; //给脉冲信号
- dat>>=1;
- DQ = 1; //给脉冲信号
- if(DQ) dat|=0x80;
- delay_18B20(10);
- }
- return(dat);
- }
- void ds1820wr(unsigned char wdata)/*写数据*/
- {
- unsigned char i=0;
- for (i=8; i>0; i--)
- {
- DQ = 0;
- DQ = wdata&0x01;
- delay_18B20(25);
- DQ = 1;
- wdata>>=1;
- }
- }
- //读取DS18B20温度值
- //入口参数:无
- //返回值:温度值
- unsigned int read_18b20(void)/*读取温度值并转换*/
- {
- unsigned char a,b;
- unsigned char tem;
- ds1820rst();
- ds1820wr(0xcc);//*跳过读序列号*/
- ds1820wr(0x44);//*启动温度转换*/
- ds1820rst();
- ds1820wr(0xcc);//*跳过读序列号*/
- ds1820wr(0xbe);//*读取温度*/
- a=ds1820rd();
- b=ds1820rd();
- tem=((b<<4)|(a>>4)); //将高低字节组合成字
- //Delay_ms(50);
- return tem; //完成温度转换
- }
- /*-----------------------------------------------
- 数码管
- -----------------------------------------------*/
- //共阴数码管
- //动态扫描
- void display(unsigned char Data)
- {
- //P3 = 0;
- ONE = 1; //打开个位位选
- TEN = 0;
- P3 = table[Data/10];//送个位
- Delay_ms(5);//延时
- P3 = 0; //防止重影
- //Delay_us(5);
-
- TEN = 1;
- ONE = 0;
- P3 = table[Data%10];
- Delay_ms(5);
- P3 = 0;
- //Delay_us(5);
- }
- /*-----------------------------------------------
- 按键处理函数
- -----------------------------------------------*/
- char S_F=0;
- unsigned char Key_Value(void)
- {
- if(!KEY_ADD || !KEY_DEC||!KEY_SET) // 检测是否有任意按键按下
- {
- Delay_ms(20);
- Set_Flag = 1; //切换到显示设置值
- if(!KEY_ADD) //如果检测到低电平,说明按键按下
- {
- Delay_ms(10); //延时去抖,一般10-20ms
- if(!KEY_ADD) //再次确认按键是否按下,没有按下则退出
- {
- while(!KEY_ADD);//如果确认按下按键等待按键释放,没有释放则一直等待
- {
- if(num<99) //加操作
- num++;
- }
- }
- }
- if(!KEY_DEC) //如果检测到低电平,说明按键按下
- {
- Delay_ms(10); //延时去抖,一般10-20ms
- if(!KEY_DEC) //再次确认按键是否按下,没有按下则退出
- {
- while(!KEY_DEC);//如果确认按下按键等待按键释放,没有释放则一直等待
- {
- if(num>0) //减操作
- num--;
- }
- }
- }
- if(!KEY_SET) //如果检测到低电平,说明按键按下
- {
- Delay_ms(10); //延时去抖,一般10-20ms
- if(!KEY_SET) //再次确认按键是否按下,没有按下则退出
- {
- //Set_Flag = 0;
- while(!KEY_SET);//如果确认按下按键等待按键释放,没有释放则一直等待
- {
- //将当前值作为设定值
-
- //Set_Flag = 0; //切换到显示温度值
- }
- if(S_F)
- Set_Flag=0;
- }
- }
- }
-
- Set_Value = num;
- return (num);
- }
- /*-----------------------------------------------
- 24C02初始化
- -----------------------------------------------*/
- /*------------------------------------------------
- 启动总线
- ------------------------------------------------*/
- void Start_I2c()
- {
- SDA=1; //发送起始条件的数据信号
- _Nop();
- SCL=1;
- _Nop(); //起始条件建立时间大于4.7us,延时
- _Nop();
- _Nop();
- _Nop();
- _Nop();
- SDA=0; //发送起始信号
- _Nop(); //起始条件锁定时间大于4μ
- _Nop();
- _Nop();
- _Nop();
- _Nop();
- SCL=0; //钳住I2C总线,准备发送或接收数据
- _Nop();
- _Nop();
- }
- /*------------------------------------------------
- 结束总线
- ------------------------------------------------*/
- void Stop_I2c()
- {
- SDA=0; //发送结束条件的数据信号
- _Nop(); //发送结束条件的时钟信号
- SCL=1; //结束条件建立时间大于4μ
- _Nop();
- _Nop();
- _Nop();
- _Nop();
- _Nop();
- SDA=1; //发送I2C总线结束信号
- _Nop();
- _Nop();
- _Nop();
- _Nop();
- }
- /*----------------------------------------------------------------
- 字节数据传送函数
- 函数原型: void SendByte(unsigned char c);
- 功能: 将数据c发送出去,可以是地址,也可以是数据,发完后等待应答,并对
- 此状态位进行操作.(不应答或非应答都使ack=0 假)
- 发送数据正常,ack=1; ack=0表示被控器无应答或损坏。
- ------------------------------------------------------------------*/
- void SendByte(unsigned char c)
- {
- unsigned char BitCnt;
-
- for(BitCnt=0;BitCnt<8;BitCnt++) //要传送的数据长度为8位
- {
- if((c<<BitCnt)&0x80)SDA=1; //判断发送位
- else SDA=0;
- _Nop();
- SCL=1; //置时钟线为高,通知被控器开始接收数据位
- _Nop();
- _Nop(); //保证时钟高电平周期大于4μ
- _Nop();
- _Nop();
- _Nop();
- SCL=0;
- }
-
- _Nop();
- _Nop();
- SDA=1; //8位发送完后释放数据线,准备接收应答位
- _Nop();
- _Nop();
- SCL=1;
- _Nop();
- _Nop();
- _Nop();
- if(SDA==1)ack=0;
- else ack=1; //判断是否接收到应答信号
- SCL=0;
- _Nop();
- _Nop();
- }
- /*----------------------------------------------------------------
- 字节数据传送函数
- 函数原型: unsigned char RcvByte();
- 功能: 用来接收从器件传来的数据,并判断总线错误(不发应答信号),
- 发完后请用应答函数。
- ------------------------------------------------------------------*/
- unsigned char RcvByte()
- {
- unsigned char retc;
- unsigned char BitCnt;
-
- retc=0;
- SDA=1; //置数据线为输入方式
- for(BitCnt=0;BitCnt<8;BitCnt++)
- {
- _Nop();
- SCL=0; //置时钟线为低,准备接收数据位
- _Nop();
- _Nop(); //时钟低电平周期大于4.7us
- _Nop();
- _Nop();
- _Nop();
- SCL=1; //置时钟线为高使数据线上数据有效
- _Nop();
- _Nop();
- retc=retc<<1;
- if(SDA==1)retc=retc+1; //读数据位,接收的数据位放入retc中
- _Nop();
- _Nop();
- }
- SCL=0;
- _Nop();
- _Nop();
- return(retc);
- }
- /*----------------------------------------------------------------
- 应答子函数
- 原型: void Ack_I2c(void);
-
- ----------------------------------------------------------------*/
- void Ack_I2c(void)
- {
-
- SDA=0;
- _Nop();
- _Nop();
- _Nop();
- SCL=1;
- _Nop();
- _Nop(); //时钟低电平周期大于4μ
- _Nop();
- _Nop();
- _Nop();
- SCL=0; //清时钟线,钳住I2C总线以便继续接收
- _Nop();
- _Nop();
- }
- /*----------------------------------------------------------------
- 非应答子函数
- 原型: void NoAck_I2c(void);
-
- ----------------------------------------------------------------*/
- void NoAck_I2c(void)
- {
-
- SDA=1;
- _Nop();
- _Nop();
- _Nop();
- SCL=1;
- _Nop();
- _Nop(); //时钟低电平周期大于4μ
- _Nop();
- _Nop();
- _Nop();
- SCL=0; //清时钟线,钳住I2C总线以便继续接收
- _Nop();
- _Nop();
- }
- /*----------------------------------------------------------------
- 向有子地址器件发送多字节数据函数
- 函数原型: bit ISendStr(unsigned char sla,unsigned char suba,ucahr *s,unsigned char no);
- 功能: 从启动总线到发送地址,子地址,数据,结束总线的全过程,从器件
- 地址sla,子地址suba,发送内容是s指向的内容,发送no个字节。
- 如果返回1表示操作成功,否则操作有误。
- 注意: 使用前必须已结束总线。
- ----------------------------------------------------------------*/
- bit ISendStr(unsigned char sla,unsigned char suba,unsigned char *s,unsigned char no)
- {
- unsigned char i;
- Start_I2c(); //启动总线
- SendByte(sla); //发送器件地址
- if(ack==0)return(0);
- SendByte(suba); //发送器件子地址
- if(ack==0)return(0);
- for(i=0;i<no;i++)
- {
- SendByte(*s); //发送数据
- Delay_ms(1);
- if(ack==0)return(0);
- s++;
- }
- Stop_I2c(); //结束总线
- return(1);
- }
- /*----------------------------------------------------------------
- 向有子地址器件读取多字节数据函数
- 函数原型: bit ISendStr(unsigned char sla,unsigned char suba,ucahr *s,unsigned char no);
- 功能: 从启动总线到发送地址,子地址,读数据,结束总线的全过程,从器件
- 地址sla,子地址suba,读出的内容放入s指向的存储区,读no个字节。
- 如果返回1表示操作成功,否则操作有误。
- 注意: 使用前必须已结束总线。
- ----------------------------------------------------------------*/
- bit IRcvStr(unsigned char sla,unsigned char suba,unsigned char *s,unsigned char no)
- {
- unsigned char i;
- Start_I2c(); //启动总线
- SendByte(sla); //发送器件地址
- if(ack==0)return(0);
- SendByte(suba); //发送器件子地址
- if(ack==0)return(0);
- Start_I2c();
- SendByte(sla+1);
- if(ack==0)return(0);
- for(i=0;i<no-1;i++)
- {
- *s=RcvByte(); //发送数据
- Ack_I2c(); //发送就答位
- s++;
- }
- *s=RcvByte();
- NoAck_I2c(); //发送非应位
- Stop_I2c(); //结束总线
- ……………………
- …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码
所有资料51hei提供下载:
tempature.zip
(98.2 KB, 下载次数: 62)
|