找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 3435|回复: 4
收起左侧

PIC16f877a单片机DS18b20源程序

[复制链接]
ID:615929 发表于 2019-9-24 22:16 | 显示全部楼层 |阅读模式
//调试总结:
//显著的问题是,写时序、读时序中,PIC MCU向总线写1是通过改方向为输入方向由上拉电阻拉高数据线实现的,而非在输出方向下输出1,与AVR不同
//某IO口8位未全使用时,对整个IO口读取进行位运算无效
//使用if(dat2&0xf8==0xf8)时,进错分支导致显示乱码仍未找到原因,用if(dat2>=240)代替正常
  1. #include<pic.h>
  2. #define uchar unsigned char
  3. #define uint unsigned int
  4. #define rs_h (PORTC|=0x01)
  5. #define rs_l (PORTC&=0xfe)
  6. #define rs_o (TRISC&=0xfe)
  7. #define rw_h (PORTC|=0x02)
  8. #define rw_l (PORTC&=0xfd)
  9. #define rw_o (TRISC&=0xfd)
  10. #define en_h (PORTC|=0x04)
  11. #define en_l (PORTC&=0xfb)
  12. #define en_o (TRISC&=0xfb)
  13. #define temp_h (PORTC|=0x08)
  14. #define temp_l (PORTC&=0xf7)
  15. #define temp_o (TRISC&=0xf7)
  16. #define temp_i (TRISC|=0x08)
  17. #define led_o (TRISC&=0xef)
  18. #define led_l (PORTC&=0xef)
  19. #define led_h (PORTC|=0x10)
  20. #define LCD PORTB
  21. uchar dat1,dat2;//保存读出的温度z
  22. unsigned long int dat;
  23. void delayms(uint x) //4M晶振下,延时1ms
  24. {
  25.         uint y,z;
  26.         for(y=x;y>0;y--)
  27.                 for(z=110;z>0;z--);
  28. }
  29. void Ds18b20_reset(void)//DS18B20初始化
  30. {
  31.         uint count;
  32.         uchar i,flag=1;
  33.         temp_o;
  34.         temp_l;
  35.         for(count=60;count>0;count--);//延时480us
  36.         temp_i;
  37.         while(flag)
  38.         {
  39.                 //temp=PORTC;//此例中,C口部分引脚未使用处于高阻态,对整个C口的读取无效,所以if(RC3)不能换成if(temp&0x08==0x08)
  40.                 if(RC3)//temp&0x08==0x08)
  41.                         flag=1;
  42.                 else
  43.                         flag=0;        
  44.         }
  45.         led_o;
  46.         led_l;//开指示灯
  47.         for(count=60;count>0;count--);//延时480us
  48. }
  49. void Ds18b20_write(uchar datt)//向DS18B20写一个字节
  50. {
  51.         uchar count;
  52.         uchar i;
  53.         temp_o;
  54.         for(i=8;i>0;i--)
  55.         {
  56.                 temp_o;
  57.                 temp_l;
  58.                 for(count=1;count>0;count--);
  59.                 //temp_h;//不能有此语句
  60.                 if(datt&0x01==0x01)
  61.                         temp_i;
  62.                 else
  63.                 {        
  64.                         temp_o;
  65.                         temp_l;
  66.                 }
  67.                 for(count=23;count>0;count--);//延时60us
  68.                 temp_i;
  69.                 for(count=1;count>0;count--);
  70.                 datt>>=1;        
  71.         }        
  72. }
  73. uchar Ds18b20_read(void) //从DS18B20读一个字节
  74. {
  75.         uchar i,datt;
  76.         uchar count;
  77.         for(i=8;i>0;i--)
  78.         {
  79.                 datt>>=1;
  80.                 temp_o;
  81.                 temp_l;
  82.                 for(count=1;count>0;count--);
  83.                 temp_i;//改为输入方向时,上拉电阻把数据线拉高,释放总线,此语句必须有,参考datasheet的P15
  84.                 for(count=1;count>0;count--);
  85.                 if(RC3)//(PORTC&0x08==0x08)//换成(PORTC&0x08==0x08)后程序不正确
  86.                         datt|=0x80;
  87.                 for(count=23;count>0;count--);//延时60us        
  88.         }
  89.         return datt;
  90. }
  91. void lcd_com(uchar com)//向LCD1602写命令
  92. {
  93.          rs_o;
  94.         rw_o;
  95.         en_o;
  96.         TRISB=0x00;//配置RB为输出方向
  97.         rs_l;        
  98.         rw_l;
  99.         LCD=com;
  100.         delayms(1);
  101.         en_h;
  102.         delayms(1);        
  103.         en_l;
  104.         delayms(1);               
  105. }
  106. void lcd_dat(uchar dat)//向LCD1602写数据
  107. {
  108.          rs_o;
  109.         rw_o;
  110.         TRISB=0x00;//配置RB为输出方向
  111.         en_o;
  112.         rs_h;        
  113.         rw_l;
  114.         LCD=dat;
  115.         delayms(1);
  116.         en_h;
  117.         delayms(1);
  118.         en_l;
  119.         delayms(1);        
  120. }
  121. void lcd_write(uchar c,uchar r,uchar dat)//向LCD1602指定行、指定列、写数据
  122. {
  123.         lcd_com(0x80+0x40*c+r);
  124.         lcd_dat(dat);
  125.         delayms(1);
  126. }
  127. void lcd_init(void)//LCD1602初始化,初始化后第一行显示temperature:,第二行显示.C
  128. {
  129.         lcd_com(0x38);
  130.         lcd_com(0x0c);
  131.         lcd_com(0x06);
  132.         lcd_write(0,2,0x54);
  133.         lcd_write(0,3,0x65);
  134.         lcd_write(0,4,0x6d);
  135.         lcd_write(0,5,0x70);
  136.         lcd_write(0,6,0x65);
  137.         lcd_write(0,7,0x72);
  138.         lcd_write(0,8,0x61);
  139.         lcd_write(0,9,0x74);
  140.         lcd_write(0,10,0x75);
  141.         lcd_write(0,11,0x72);
  142.         lcd_write(0,12,0x65);
  143.         lcd_write(0,13,0x3a);
  144.         lcd_write(1,11,0xdf);
  145.         lcd_write(1,12,0x43);
  146. }
  147. void show(void)//把温度值送LCD1602显示
  148. {
  149.         uchar flag;
  150.         uchar t[4];
  151.         uint temp;
  152.         if(dat2>=240)//遗留问题,温度为25时读出dat1=144,dat2=1正确,但却进入if(dat2&0xf8==0xf8)分支导致显示乱码;
  153.         {
  154.                 dat= (~(dat2*256+dat1)+1)*(0.0625*10);//取反加一,保留一位小数
  155.                 flag=1;
  156.         }
  157.         else
  158.         {
  159.                 dat=(dat2*256+dat1)*(0.0625*10);
  160.                 flag=0;
  161.         };
  162.         temp=dat%10;
  163.         t[0]=(0x30+temp);
  164.         temp=dat%100;
  165.         temp=temp/10;
  166.         t[1]=(0x30+temp);
  167.         temp=dat%1000;
  168.         temp=temp/100;
  169.         t[2]=(0x30+temp);
  170.         temp=dat/1000;
  171.         t[3]=(0x30+temp);
  172.         if(flag==1)//负温度显示
  173.         {
  174.                 lcd_write(1,10,t[0]);
  175.                 lcd_write(1,9,0xa5);
  176.                 lcd_write(1,8,t[1]);
  177.                 lcd_write(1,7,t[2]);
  178.                 lcd_write(1,6,t[3]);
  179.                 lcd_write(1,5,0x2d);
  180.         }
  181.         if(flag==0)//正温度显示
  182.         {
  183.                 lcd_write(1,10,t[0]);
  184.                 lcd_write(1,9,0xa5);
  185.                 lcd_write(1,8,t[1]);
  186.                 lcd_write(1,7,t[2]);
  187.                 lcd_write(1,6,t[3]);
  188.                 lcd_write(1,5,0x20);//显示空格,刷掉负号
  189.         }
  190. }
  191. void main(void)
  192. {
  193.         lcd_init();
  194.         while(1)
  195.         {
  196.                 Ds18b20_reset();
  197.                 Ds18b20_write(0xcc);
  198.                 Ds18b20_write(0x44);//发送温度转换命令
  199.                 delayms(1000);//延时1s,等待温度转换完成
  200.                 Ds18b20_reset();
  201.                 Ds18b20_write(0xcc);
  202.                 Ds18b20_write(0xbe);//发送读温度寄存器命令
  203.                 dat1=Ds18b20_read();
  204.                 dat2=Ds18b20_read();
  205.                 show();
  206.                 led_h;//关指示灯
  207.                 delayms(2000);
  208.         }
  209. }
复制代码



PICds18b20(4M).zip

87.02 KB, 下载次数: 36, 下载积分: 黑币 -5

回复

使用道具 举报

ID:592524 发表于 2019-9-26 21:21 | 显示全部楼层
用什么编译器?
回复

使用道具 举报

ID:23844 发表于 2021-7-18 21:37 | 显示全部楼层
bbb168 发表于 2019-9-26 21:21
用什么编译器?

我估计是MPLAB,看那个#include<pic.h>猜的
回复

使用道具 举报

ID:955831 发表于 2021-7-28 15:37 | 显示全部楼层
bbb168 发表于 2019-9-26 21:21
用什么编译器?

应该是PICC编译器
回复

使用道具 举报

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

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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