找回密码
 注册会员
更新自动建库工具PCB Footprint Expert 2024.04 Pro / Library Expert 破解版

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

[复制链接]
慧龙 发表于 2010-5-7 11:09:23 | 显示全部楼层 |阅读模式

本文包含原理图、PCB、源代码、封装库、中英文PDF等资源

您需要 登录 才可以下载或查看,没有账号?注册会员

×
该程序完成DS18B20的温度采集,然后将采集到的温度值发送到串口,在计算机上通过串口助手可以观察到采集结果。
这也是我们为什么之前早早的就讲解串口通信的原因。在单片机的学习过程中,串口通信是一个很好的辅助调试手段,我们可以在程序的不同位置放置串口数据发送程序,从而实现程序调试功能,这样调试比直接用仿真器调试来的快捷方便,另外LED发光二极管,蜂鸣器等都可以作为辅助调试工具,我们可以在程序容易出现问题的地方防止一些指示(如发光二极管的亮灭,蜂鸣器的鸣叫,串口发送相应信息),通过这些指示我们可以很方便的判断程序执行结果是否正确。
  1. #include <AVR/io.h>
  2. #include <util/delay.h>
  3. #include <avr/interrupt.h> //中断函数头文件
  4. //××××××××××××引脚宏定义×××××××××××××
  5. //18B20定义
  6. #define SET_DQ (PORTE) |= (1 << (PE7)) // 18b20 高电平
  7. #define CLR_DQ (PORTE) &=~(1 << (PE7)) // 18b20 低电平
  8. #define DQ_IN (PINE) & (1<<(PE7)) // 18b20信号输入
  9. #define SET_OUT (DDRE) |= (1<<(PE7)) //PA2定义成输出
  10. #define SET_IN (DDRE) &=~(1<<(PE7)) //PA2定义成输入

  11. //常量声明
  12. #define BAUD 9600
  13. //全局变量声明
  14. unsigned char Temp_H,Temp_L,OK_Flag; //温度高位,低位,复位成功标志
  15. //函数声明
  16. void Delayus(unsigned int lus); //us延时函数
  17. void Delayms(unsigned int lms); //ms延时函数
  18. void Port_DS18b20(void); //DS18B20端口配置
  19. void Port_Init(void); //端口初始化配置
  20. void Usart_Init(void); //USART寄存器设置
  21. void Usart_PutChar(unsigned char cTXData); //字节发送函数
  22. void Usart_PutString(unsigned char *pcString); //字符串发送函数
  23. unsigned char DS18B20_Init(void); //DS18B20初始化
  24. unsigned char Read_18b20(void); //读18b20
  25. void Write_18b20(unsigned char dat); //写18b20
  26. int main(void)
  27. {
  28. unsigned char i;
  29. unsigned int tempint,tempint1,tempint2,tempint3,tempint4;
  30. //分别存储温度整数值,整数值的千,百,十,个位
  31. unsigned int temppoint,temppoint1,temppoint2,temppoint3,temppoint4;
  32. //分别存储温度小数值,小数值的千,百,十,个位

  33. Port_Init(); //端口初始化
  34. Usart_Init(); //串口初始化
  35. Port_DS18b20(); //DS18B20端口初始化

  36. tempint = 0; //变量初始化
  37. temppoint=0;
  38. Temp_H = 0;
  39. Temp_L = 0;
  40. OK_Flag = 0;

  41. Usart_PutString("DS18B20 温度测量实验");
  42. Usart_PutChar(0x0D);
  43. Usart_PutChar(0x0A); //结尾发送回车换行


  44. sei(); //使能全局中断

  45. while(1)
  46. {
  47. /*
  48. if(DS18B20_Init()) //判断DS18B20复位是否成功
  49. {
  50. PORTB = 0x01;
  51. }
  52. else
  53. {
  54. PORTB = 0x02;
  55. }
  56. */
  57. cli(); //关中断

  58. DS18B20_Init(); //初始化DS18B20

  59. Write_18b20(0Xcc); //发送ROM指令,跳过ROM匹配

  60. Write_18b20(0X44); // 发送温度转换命令

  61. for(i=0;i<50;i++) //延时1S,等转换完成
  62. {
  63. Delayms(20);
  64. }

  65. DS18B20_Init(); //初始化DS18B20

  66. Write_18b20(0Xcc); //发送ROM指令,跳过ROM匹配

  67. Write_18b20(0Xbe); //发送读取暂存器指令

  68. Temp_L = Read_18b20(); //获得温度的低位

  69. Temp_H = Read_18b20(); //获得温度的高位

  70. if(Temp_H & 0x08) //判断温度的正负
  71. {
  72. Temp_H = ~Temp_H; //负温度。取反加1
  73. Temp_L = ~Temp_L; //

  74. SREG |= ~(1 << SREG_C); //清零进位位标志
  75. Temp_L++; //温度低字节加1
  76. if(SREG & (1 << SREG_C)) //有进位吗?
  77. {
  78. Temp_H++; //有进位,则温度高字节加1
  79. }

  80. }

  81. tempint = ((Temp_H << 4) & 0x70) | (Temp_L >> 4); //获得温度的整数位

  82. tempint1 = tempint / 1000; //千位
  83. tempint2 = tempint % 1000 / 100; //百位
  84. tempint3 = tempint % 100 / 10; //十位
  85. tempint4 = tempint % 10; //个位

  86. temppoint = Temp_L & 0x0f; //取出温度的小数位
  87. temppoint = (temppoint * 625); //小数位乘以0.625得出温度的小数位值,在此扩大1000
  88. //倍,得出温度的4位小数位,显示的时候加小数点

  89. temppoint1 = temppoint / 1000; //千位
  90. temppoint2 = temppoint % 1000 / 100; //百位
  91. temppoint3 = temppoint % 100 / 10; //十位
  92. temppoint4 = temppoint % 10; //个位

  93. Usart_PutString("当前环境温度为:"); //发送温度值到上位机

  94. if(!(tempint1)) //高位为零,则不显示
  95. {
  96. Usart_PutChar(' ');
  97. if(!(tempint2))
  98. {
  99. Usart_PutChar(' ');
  100. }
  101. else
  102. {
  103. Usart_PutChar(tempint2 + 0x30);
  104. }
  105. if(!(tempint3))
  106. {
  107. Usart_PutChar(' ');
  108. }
  109. else
  110. {
  111. Usart_PutChar(tempint3 + 0x30);
  112. }
  113. //Usart_PutChar(tempint4 + 0x30);
  114. }
  115. else
  116. {
  117. Usart_PutChar(tempint1 + 0x30);
  118. Usart_PutChar(tempint2 + 0x30);
  119. Usart_PutChar(tempint3 + 0x30);
  120. }
  121. Usart_PutChar(tempint4 + 0x30);
  122. Usart_PutChar('.'); //显示小数点

  123. Usart_PutChar(temppoint1 + 0x30); //显示小数位
  124. Usart_PutChar(temppoint2 + 0x30);
  125. Usart_PutChar(temppoint3 + 0x30);
  126. Usart_PutChar(temppoint4 + 0x30);

  127. Usart_PutChar(' '); //不显示,空一格
  128. Usart_PutChar('o'); //显示温度的符号。由于实在找不到温度那个再上面的小o,
  129. Usart_PutChar('C'); //只好用普通的小写o来代替了。
  130. Usart_PutChar(0x0D);
  131. Usart_PutChar(0x0A); //结尾发送回车换行

  132. sei(); //开中断

  133. for(i=0;i<200;i++) //延时4S,再进行温度转换
  134. {
  135. Delayms(20);
  136. }
  137. }
  138. }
  139. //端口状态初始化设置函数
  140. void Port_Init()
  141. {
  142. PORTD = 0X00; //USART的发送接收端口分别为PD0和PD1
  143. DDRD |= (1 << PD3); //PD0为接收端口,置为输入口;PD1为发送端口,置为输出口
  144. PORTB = 0x00;
  145. DDRB = 0xff;
  146. }
  147. void Port_DS18b20()
  148. {
  149. DDRE &= ~(1 << PE7); // 输入模式(上电时为高电平)
  150. PORTE &= ~(1 << PE7); // 输出锁存器写0,以后不再更改
  151. }
  152. //USART寄存器配置函数
  153. void Usart_Init()
  154. {
  155. UCSR1A = 0X00;
  156. UCSR1C |= (1 << UCSZ11) | (1 << UCSZ10); //异步,数据格式8,N,1

  157. UBRR1L = (F_CPU / BAUD / 16 - 1) % 256; //波特率设置
  158. UBRR1H = (F_CPU / BAUD / 16 - 1) / 256;
  159. UCSR1B |= (1 << RXCIE1) | (1 << RXEN1) | (1 << TXEN1); //发送使能

  160. }
  161. //字节发送函数
  162. void Usart_PutChar(unsigned char cTXData)
  163. {
  164. while( !(UCSR1A & (1 << UDRE1)) ); //只有数据寄存器为空时才能发送数据
  165. UDR1 = cTXData; //发送数据送USART I/O数据寄存器-UDR
  166. }
  167. //接收中断函数
  168. ISR(USART1_RX_vect)
  169. {
  170. unsigned char Rev;
  171. Rev = UDR1; //从USART I/O数据寄存器-UDR中读出数据
  172. Usart_PutChar(Rev); //将接收到的数据发送
  173. }

  174. void Usart_PutString(unsigned char *pcString)
  175. {
  176. while (*pcString)
  177. {
  178. Usart_PutChar(*pcString++);
  179. }
  180. }
  181. //DS18B20初始化
  182. unsigned char DS18B20_Init()
  183. {
  184. SET_OUT; //PA2设置为输出口(相当于拉低数据线上的电平)

  185. Delayus(490); //延时大于480us

  186. SET_IN; //输入 释放数据线(相当于拉高数据线上的电平)

  187. Delayus(68); //延时大于60US,

  188. //while(DQ_IN); //可以用两个while()死循环来判断复位是否成功,当数据线被拉低,说明
  189. //while(!(DQ_IN)); //18b20开始复位应答,当数据线变高,说明应答完毕

  190. if(DQ_IN) //判断DS18B20是否拉低数据线
  191. {
  192. OK_Flag = 0; // 数据线是高?复位失败
  193. }
  194. else
  195. {
  196. OK_Flag = 1; // 数据线是低?复位成功
  197. }
  198. Delayus(422); //有复位应答信号后,应当再延时一段时间(480-68),以等待应答完毕

  199. return OK_Flag; //返回复位标志
  200. }
  201. //从DS18B20读取一个字节数据
  202. unsigned char Read_18b20()
  203. {
  204. unsigned char i;
  205. unsigned char dat = 0; // dat用于存储读到的数据,先清零

  206. for(i = 0;i < 8;i++) //共读8位数据,构成一个字节
  207. {
  208. SET_OUT; //定义为输出(拉低数据线)

  209. Delayus(2); //拉低2微秒

  210. SET_IN; //定义成输入,读入数据(同时也相当于拉高数据线)

  211. Delayus(4); //延时
  212. dat = dat >> 1; //数据右移,读顺序:先低后高
  213. if(DQ_IN) //读数据,
  214. {
  215. dat |= 0x80; //如果是高,置1,右移数据
  216. }
  217. Delayus(62); //延时大于60us
  218. }
  219. return dat; //返回读到的1字节数据
  220. }
  221. //向DS18B20写1字节数据
  222. void Write_18b20(unsigned char dat)
  223. {
  224. unsigned char i;

  225. for(i = 0;i < 8;i++) //写8次,一次写1位,先写低字节
  226. {
  227. SET_OUT; //拉低数据线2us,开始写数据
  228. Delayus(2); //

  229. if(dat & 0x01) //写数据
  230. {
  231. SET_IN; //写1
  232. }
  233. else
  234. {
  235. SET_OUT; //写0
  236. }
  237. dat >>= 1; //数据右移1位,先写低位
  238. Delayus(62); //延时大于60us

  239. SET_IN; //拉高数据线
  240. Delayus(2); //写两位数据的时间间隔

  241. }
  242. }
  243. //us级别的延时函数
  244. void Delayus(unsigned int lus)
  245. {
  246. while(lus--)
  247. {
  248. _delay_loop_2(4); //_delay_loop_2(1)是延时4个时钟周期,参数为3则延时12
  249. //个时钟周期,本实验用12M晶体,则12个时钟周期为12/12=1us
  250. }
  251. }
  252. //ms级别的延时函数
  253. void Delayms(unsigned int lms)
  254. {
  255. while(lms--)
  256. {
  257. Delayus(1000); //延时1ms
  258. }
  259. }
复制代码
*滑块验证:
您需要登录后才可以回帖 登录 | 注册会员

本版积分规则

QQ|手机版|MCU资讯论坛 ( 京ICP备18035221号-2 )|网站地图

GMT+8, 2024-12-23 12:48 , Processed in 0.095530 second(s), 10 queries , Redis On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

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