hrefspace

 找回密码
 立即注册
搜索
热搜: PHP PS 程序设计
查看: 653|回复: 0

自学AVR单片机二十一(DS18B20温度采集的完整程序)

[复制链接]

494

主题

494

帖子

1506

积分

版主

Rank: 7Rank: 7Rank: 7

积分
1506
发表于 2024-2-19 00:14:00 | 显示全部楼层 |阅读模式
该程序完成DS18B20的温度采集,然后将采集到的温度值发送到串口,在计算机上通过串口助手可以观察到采集结果。
这也是我们为什么之前早早的就讲解串口通信的原因。在单片机的学习过程中,串口通信是一个很好的辅助调试手段,我们可以在程序的不同位置放置串口数据发送程序,从而实现程序调试功能,这样调试比直接用仿真器调试来的快捷方便,另外LED发光二极管,蜂鸣器等都可以作为辅助调试工具,我们可以在程序容易出现问题的地方防止一些指示(如发光二极管的亮灭,蜂鸣器的鸣叫,串口发送相应信息),通过这些指示我们可以很方便的判断程序执行结果是否正确。
  1. #include <[url=http://www.mcuzx.net]AVR[/url]/io.h> #include <util/delay.h>#include <avr/interrupt.h> //中断函数头文件//××××××××××××引脚宏定义×××××××××××××//18B20定义#define SET_DQ (PORTE) |= (1 << (PE7)) // 18b20 高电平#define CLR_DQ (PORTE) &=~(1 << (PE7)) // 18b20 低电平#define DQ_IN (PINE) & (1<<(PE7)) // 18b20信号输入#define SET_OUT (DDRE) |= (1<<(PE7)) //PA2定义成输出#define SET_IN (DDRE) &=~(1<<(PE7)) //PA2定义成输入//常量声明#define BAUD 9600//全局变量声明unsigned char Temp_H,Temp_L,OK_Flag; //温度高位,低位,复位成功标志//函数声明void Delayus(unsigned int lus); //us延时函数void Delayms(unsigned int lms); //ms延时函数void Port_DS18b20(void); //DS18B20端口配置void Port_Init(void); //端口初始化配置void Usart_Init(void); //USART寄存器设置void Usart_PutChar(unsigned char cTXData); //字节发送函数void Usart_PutString(unsigned char *pcString); //字符串发送函数unsigned char DS18B20_Init(void); //DS18B20初始化unsigned char Read_18b20(void); //读18b20void Write_18b20(unsigned char dat); //写18b20int main(void) {unsigned char i;unsigned int tempint,tempint1,tempint2,tempint3,tempint4;//分别存储温度整数值,整数值的千,百,十,个位unsigned int temppoint,temppoint1,temppoint2,temppoint3,temppoint4; //分别存储温度小数值,小数值的千,百,十,个位Port_Init(); //端口初始化Usart_Init(); //串口初始化Port_DS18b20(); //DS18B20端口初始化tempint = 0; //变量初始化temppoint=0;Temp_H = 0;Temp_L = 0;OK_Flag = 0;Usart_PutString("DS18B20 温度测量实验");Usart_PutChar(0x0D);Usart_PutChar(0x0A); //结尾发送回车换行sei(); //使能全局中断 while(1){ /*if(DS18B20_Init()) //判断DS18B20复位是否成功{PORTB = 0x01;}else{PORTB = 0x02;}*/cli(); //关中断DS18B20_Init(); //初始化DS18B20Write_18b20(0Xcc); //发送ROM指令,跳过ROM匹配Write_18b20(0X44); // 发送温度转换命令 for(i=0;i<50;i++) //延时1S,等转换完成{Delayms(20);}DS18B20_Init(); //初始化DS18B20Write_18b20(0Xcc); //发送ROM指令,跳过ROM匹配Write_18b20(0Xbe); //发送读取暂存器指令Temp_L = Read_18b20(); //获得温度的低位Temp_H = Read_18b20(); //获得温度的高位if(Temp_H & 0x08) //判断温度的正负{ Temp_H = ~Temp_H; //负温度。取反加1Temp_L = ~Temp_L; //SREG |= ~(1 << SREG_C); //清零进位位标志Temp_L++; //温度低字节加1if(SREG & (1 << SREG_C)) //有进位吗?{Temp_H++; //有进位,则温度高字节加1}} tempint = ((Temp_H << 4) & 0x70) | (Temp_L >> 4); //获得温度的整数位 tempint1 = tempint / 1000; //千位 tempint2 = tempint % 1000 / 100; //百位tempint3 = tempint % 100 / 10; //十位tempint4 = tempint % 10; //个位temppoint = Temp_L & 0x0f; //取出温度的小数位temppoint = (temppoint * 625); //小数位乘以0.625得出温度的小数位值,在此扩大1000//倍,得出温度的4位小数位,显示的时候加小数点temppoint1 = temppoint / 1000; //千位 temppoint2 = temppoint % 1000 / 100; //百位temppoint3 = temppoint % 100 / 10; //十位temppoint4 = temppoint % 10; //个位Usart_PutString("当前环境温度为:"); //发送温度值到上位机if(!(tempint1)) //高位为零,则不显示{Usart_PutChar(' ');if(!(tempint2)){Usart_PutChar(' ');}else{Usart_PutChar(tempint2 + 0x30);}if(!(tempint3)){Usart_PutChar(' '); }else {Usart_PutChar(tempint3 + 0x30);}//Usart_PutChar(tempint4 + 0x30);}else{Usart_PutChar(tempint1 + 0x30);Usart_PutChar(tempint2 + 0x30);Usart_PutChar(tempint3 + 0x30);}Usart_PutChar(tempint4 + 0x30);Usart_PutChar('.'); //显示小数点Usart_PutChar(temppoint1 + 0x30); //显示小数位Usart_PutChar(temppoint2 + 0x30);Usart_PutChar(temppoint3 + 0x30);Usart_PutChar(temppoint4 + 0x30);Usart_PutChar(' '); //不显示,空一格Usart_PutChar('o'); //显示温度的符号。由于实在找不到温度那个再上面的小o,Usart_PutChar('C'); //只好用普通的小写o来代替了。Usart_PutChar(0x0D);Usart_PutChar(0x0A); //结尾发送回车换行 sei(); //开中断for(i=0;i<200;i++) //延时4S,再进行温度转换{Delayms(20);}}}//端口状态初始化设置函数void Port_Init(){PORTD = 0X00; //USART的发送接收端口分别为PD0和PD1DDRD |= (1 << PD3); //PD0为接收端口,置为输入口;PD1为发送端口,置为输出口PORTB = 0x00;DDRB = 0xff; }void Port_DS18b20(){DDRE &= ~(1 << PE7); // 输入模式(上电时为高电平)PORTE &= ~(1 << PE7); // 输出锁存器写0,以后不再更改}//USART寄存器配置函数void Usart_Init(){UCSR1A = 0X00; UCSR1C |= (1 << UCSZ11) | (1 << UCSZ10); //异步,数据格式8,N,1UBRR1L = (F_CPU / BAUD / 16 - 1) % 256; //波特率设置UBRR1H = (F_CPU / BAUD / 16 - 1) / 256; UCSR1B |= (1 << RXCIE1) | (1 << RXEN1) | (1 << TXEN1); //发送使能}//字节发送函数void Usart_PutChar(unsigned char cTXData){while( !(UCSR1A & (1 << UDRE1)) ); //只有数据寄存器为空时才能发送数据UDR1 = cTXData; //发送数据送USART I/O数据寄存器-UDR}//接收中断函数ISR(USART1_RX_vect){unsigned char Rev;Rev = UDR1; //从USART I/O数据寄存器-UDR中读出数据Usart_PutChar(Rev); //将接收到的数据发送}void Usart_PutString(unsigned char *pcString){while (*pcString){Usart_PutChar(*pcString++);} }//DS18B20初始化unsigned char DS18B20_Init(){ SET_OUT; //PA2设置为输出口(相当于拉低数据线上的电平) Delayus(490); //延时大于480usSET_IN; //输入 释放数据线(相当于拉高数据线上的电平)Delayus(68); //延时大于60US,//while(DQ_IN); //可以用两个while()死循环来判断复位是否成功,当数据线被拉低,说明//while(!(DQ_IN)); //18b20开始复位应答,当数据线变高,说明应答完毕if(DQ_IN) //判断DS18B20是否拉低数据线{OK_Flag = 0; // 数据线是高?复位失败}else{OK_Flag = 1; // 数据线是低?复位成功}Delayus(422); //有复位应答信号后,应当再延时一段时间(480-68),以等待应答完毕return OK_Flag; //返回复位标志}//从DS18B20读取一个字节数据unsigned char Read_18b20(){unsigned char i; unsigned char dat = 0; // dat用于存储读到的数据,先清零 for(i = 0;i < 8;i++) //共读8位数据,构成一个字节{ SET_OUT; //定义为输出(拉低数据线)Delayus(2); //拉低2微秒 SET_IN; //定义成输入,读入数据(同时也相当于拉高数据线)Delayus(4); //延时dat = dat >> 1; //数据右移,读顺序:先低后高if(DQ_IN) //读数据,{ dat |= 0x80; //如果是高,置1,右移数据}Delayus(62); //延时大于60us} return dat; //返回读到的1字节数据}//向DS18B20写1字节数据void Write_18b20(unsigned char dat){unsigned char i; for(i = 0;i < 8;i++) //写8次,一次写1位,先写低字节{SET_OUT; //拉低数据线2us,开始写数据Delayus(2); //if(dat & 0x01) //写数据{SET_IN; //写1 }else{SET_OUT; //写0 }dat >>= 1; //数据右移1位,先写低位Delayus(62); //延时大于60us SET_IN; //拉高数据线Delayus(2); //写两位数据的时间间隔} }//us级别的延时函数void Delayus(unsigned int lus){while(lus--){_delay_loop_2(4); //_delay_loop_2(1)是延时4个时钟周期,参数为3则延时12//个时钟周期,本实验用12M晶体,则12个时钟周期为12/12=1us}}//ms级别的延时函数void Delayms(unsigned int lms){while(lms--){Delayus(1000); //延时1ms}}
复制代码
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|hrefspace

GMT+8, 2024-5-3 04:16 , Processed in 0.054707 second(s), 21 queries .

Powered by hrefspace X3.4 Licensed

Copyright © 2022, hrefspace.

快速回复 返回顶部 返回列表