找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2788|回复: 9
收起左侧

单片机串口 18B20 接收 时好时坏

[复制链接]
ID:290576 发表于 2021-2-7 19:50 | 显示全部楼层 |阅读模式
开起pwm(开灯) 后 18B20 数值出错 请各位大师帮我看看   O(∩_∩)O谢谢
程序如下
  1. #include <reg51.h>
  2. #include <temp.h>
  3. #include <stdio.h>              //printf头文件
  4. #define uc unsigned char
  5. #define uint unsigned int
  6. float tp;
  7. uc Trg,off;                                   //Trg(triger) 单击键值全局变量
  8. uc Cont;                                  //Cont(continue)长击键值全局变量
  9. uc flag,Repeat,i,flag_t,flag_a,s[10]="",j=0,miao,fen,y[20]="",shi,pwm,upwm,flagpwm,flag_b,PWM_COUNT;
  10. bit lamp1;
  11. int time,Intrcnt;
  12. sbit led =P1^0; //工作指示灯
  13. sbit power=P1^1; //电源
  14. sbit lamp=P1^2; //灯
  15. sbit sound=P1^3; //耳机或音响
  16. sbit air =P1^4; //空调
  17. sbit power1=P1^5; //电源1
  18. sbit power2=P1^6; //电源2
  19. void uart();
  20. void KeyRead();
  21. void KeyProc();
  22. void LcdDisplay(int temp);

  23. void init()
  24. {
  25.         TMOD=0X22;  //双定时器都打开工作方式2
  26.         SCON=0X50;
  27.         TH1=0Xfd;    //4800的波特率
  28.         TL1=0Xfd;
  29.     TH0=0x00;  //100us
  30.     TL0=0xA4;
  31.         ET0=1;         //ET0=1;开启定时器0中断
  32.         TR0=1;
  33.         TR1=1;
  34.         EA=1;
  35.         ES=1;                 //ES=1;开启串口中断
  36. //        PS=1;       //串口中断有最高优先级
  37.         PT0=1;                //设定定时器T0为高优先级中断
  38.         P1=0x00;                //P1口全部低电平
  39.         P2=0xff;                //P2口全部高电平
  40.         upwm=0;
  41.         pwm=65;
  42.         Repeat=0;
  43.         flagpwm=0;
  44.         for(i=0;i<18;i++)
  45.         {
  46.         y[i]='g';
  47.         }
  48.         y[11]=65;
  49.         y[20]='\0';
  50. }
  51. void uart()             //串口发送
  52. {
  53.            TI=1;      //printf之前必须将T1置为1才行。
  54.         printf ("%s\n",y);//向上位机发送数据
  55.         while(!TI);                  //等待发送完毕
  56.         TI=0;                         //清除发送中断标志
  57.         flag_t=0;                //清除标志位
  58.         flag=0;                        //清除标志位
  59. }
  60. void timer0() interrupt 1 //定时器0中断函数
  61. {
  62.         time++;
  63.         Intrcnt++;
  64.          PWM_COUNT++;
  65.         if(255 == lamp1)
  66.         {
  67.            if(PWM_COUNT <= pwm){lamp=1;}      //判断是否到了点亮LED的时候           
  68.            else{lamp=0;}
  69.            if(PWM_COUNT>=115){PWM_COUNT=0;}
  70.         }
  71.         else{lamp=0;}
  72.         
  73.         if(time==3600 ) //5000比实际慢 因为运行其它程序会占用时间
  74.         {
  75.           time = 0;
  76.           led=~led;
  77.           flag_a++;
  78.                     
  79.         }
  80. }
  81. void kaiguan()
  82. {
  83.          if(flag_t==1)   
  84.          {
  85.                 if(s[0]=='*')//*灯控制符
  86.                  {
  87.                         if(s[1]=='1')
  88.                          {
  89.                                 lamp1=255;         //开灯
  90.                                 y[10]='k';
  91.                          }
  92.                         if(s[1]=='2')
  93.                          {
  94.                                 lamp1=0;        //关灯
  95.                                 y[10]='g';
  96.                                 upwm=0;               
  97.                          }
  98.                    }
  99.                 if(s[0]=='!')//*空调控制符
  100.                  {
  101.                         if(s[1]=='1')
  102.                          {
  103.                                 air=1;         //开
  104.                                 y[9]='k';
  105.                              }
  106.                         if(s[1]=='2')
  107.                           {
  108.                                 air=0;        //关
  109.                                 y[9]='g';                                                  
  110.                           }
  111.                  }
  112.                 if(s[0]=='@')//*耳机控制符
  113.                  {
  114.                         if(s[1]=='1')
  115.                           {
  116.                                 sound=1;         //耳机        
  117.                                 y[8]='k';
  118.                          }
  119.                         if(s[1]=='2')
  120.                          {
  121.                                 sound=0;        //音响
  122.                                 y[8]='g';                                                         
  123.                          }
  124.                  }
  125.                 if(s[0]=='%')//*电源1控制符
  126.                  {
  127.                         if(s[1]=='1')
  128.                           {
  129.                                 power1 = 1;         //开
  130.                                 y[7]='k';
  131.                          }
  132.                         if(s[1]=='2')
  133.                          {
  134.                                 power1=0;        //关
  135.                                 y[7]='g';                                                  
  136.                          }
  137.                  }
  138.                 if(s[0]=='^')//*电源2控制符
  139.                  {
  140.                         if(s[1]=='1')
  141.                           {
  142.                                 power2=1;         //开
  143.                                 y[6]='k';
  144.                          }
  145.                         if(s[1]=='2')
  146.                          {
  147.                                 power2=0;        //关
  148.                                 y[6]='g';                                                         
  149.                          }
  150.                  }

  151.                 if(s[0]=='


  152. )//*时间
  153.                  {
  154.                    miao=((s[1]-48)*10+s[2]-48);           //48是ASCLL码数字0
  155.                    fen=((s[3]-48)*10+s[4]-48);
  156.                    shi=((s[5]-48)*10+s[6]-48);
  157.                  }
  158.                 if(s[0]=='&')//&pwm控制符
  159.                  {               
  160.                    pwm=s[1];         //开
  161.                    y[11]=pwm;
  162.                  }
  163.                 uart();
  164.                 flag=0;
  165.         }
  166. }
  167. void shijian() //发送时间
  168. {

  169.         
  170.          if(flag_a==2)
  171.          {         
  172.           flag_a=0;
  173.           miao++;           
  174.           if(miao>59)
  175.           {
  176.                   miao=0;
  177.                 fen++;
  178.                 if(fen>59)
  179.                 {
  180.                  fen=0;
  181.                  shi++;
  182.                  if(shi>23)
  183.                  shi=0;
  184.                 }        
  185.           }
  186.           if(miao<=9)
  187.           {
  188.                   y[0]=48;         //48是ASCLL码数字0
  189.                   y[1]=48+miao;         
  190.           }
  191.           else
  192.           {
  193.                 y[0]=48+miao/10;
  194.                 if(miao%10==0)
  195.                 {
  196.                  y[1]=48;
  197.                 }
  198.                 else y[1]=48+miao%10;         
  199.           }
  200.           if(fen<=9)
  201.           {
  202.                   y[2]=48;
  203.                   y[3]=48+fen;         
  204.           }
  205.           else
  206.           {
  207.                 y[2]=48+fen/10;
  208.                 if(fen%10==0)
  209.                 {
  210.                  y[3]=48;
  211.                 }
  212.           else y[3]=48+fen%10;         
  213.           }
  214.           if(shi<=9)
  215.           {
  216.                   y[4]=48;
  217.                   y[5]=48+shi;         
  218.           }
  219.           else
  220.           {
  221.                 y[4]=48+shi/10;
  222.                 if(shi%10==0)
  223.                 {
  224.                  y[5]=48;
  225.                 }
  226.           else y[5]=48+shi%10;         
  227.           }                              
  228.           uart();
  229.           LcdDisplay(Ds18b20ReadTemp());
  230.           if(power==1)
  231.           {
  232.            off--;
  233.            if(off<15)
  234.                 power=0;           
  235.           }
  236.           y[18]=off;                    
  237.          }
  238. }
  239. void main()
  240. {        
  241.         init();
  242.         while(1)
  243.         {                        
  244.            kaiguan();  //发送当前开关状态
  245.            shijian();        //发送当前时间                           
  246.          KeyRead();  //将每个子程序都扫描一遍
  247.          KeyProc();        
  248.            while(1)
  249.          {
  250.            if(Intrcnt>600)                // 一直在等,直到20ms时间到
  251.              {
  252.                Intrcnt=0;
  253.                break;               // 返回主循环
  254.              }
  255.          }

  256.     }
  257. }
  258. void ser() interrupt 4          //串口中断函数
  259. {

  260.             
  261.         if(RI)       //接收数据,手动将RI清0
  262.         {
  263.                 RI=0;
  264.                 off=60;
  265.                 if(flag==0&&j!=0)//1.循环赋值为'\0'(字符串结尾标志符),j=0,为了第二次传递字符串是又是从头输出
  266.                         {                         //2.flag为0和j不为0时,保证是第二次及以后,传输字符串(控制输出格式)
  267.                                   for(j=0;s[j]!='#'&&j<10;j++)
  268.                                 s[j]='\0';//'\0'字符串结尾标志符
  269.                                 j=0;
  270.                   }
  271.                                 s[j]=SBUF;
  272.                                 flag=1;
  273.                 if(s[j]=='#'||j==9)//以'#'作为传送字符串的结尾符,我定义的字符数组最长为10所以9也应该结束。
  274.                         flag_t=1;
  275.                   else
  276.                         j++;
  277.         }
  278. }

  279. void KeyRead()                                        //读键获取键值
  280. {
  281.     uc ReadData = P2^0xFF;   //ReadData 临时变量,"^"按位异或运算:如果a、b两个值不相同!
  282.                                                             //则异或结果为1。如果a、b两个值相同,异或结果为0。
  283.     Trg = ReadData & (ReadData ^ Cont); //获取短按键值 按位与(&)两个数相同时才为1
  284.     Cont = ReadData;                    //获取长按键值

  285. }

  286. void KeyProc()                                                //判断键值执行相应任务
  287. {
  288.         //uc cnt_plus,cnt_plus1;                //定义2个计时变量               
  289.                 if (Trg & 1)                         //1 2 4 8 16 32 64 128
  290.                  {                                                 // 如果按下的是1 ,而且你长按这按键也没有用,
  291.                           power=1;
  292.                         off=255;        
  293.                  }
  294.                 if(Trg &4)
  295.                  {
  296.                    air=~air;
  297.                    if(air==1)
  298.                    y[9]='k';
  299.                    else
  300.                            y[9]='g';
  301.                         uart();                          
  302.                  }
  303.                 if(Trg &8)
  304.                  {
  305.                    sound=~sound;
  306.                    if(sound==1)
  307.                    y[8]='k';
  308.                    else
  309.                            y[8]='g';
  310.                         uart();                           
  311.                  }
  312.                 if(Trg &16)
  313.                  {
  314.                    power1=~power1;
  315.                    if(power1==1)
  316.                    y[7]='k';
  317.                    else
  318.                            y[7]='g';
  319.                         uart();                           
  320.                  }
  321.                 if(Trg &32)
  322.                  {
  323.                    power2=~power2;
  324.                    if(power2==1)
  325.                    y[6]='k';
  326.                    else
  327.                    y[6]='g';
  328.                    uart();                                                     
  329.                  }                 
  330.         if (Cont & 2 )        //如果按着不放
  331.         {
  332.                         flagpwm=0;
  333.                         if(0 == upwm)
  334.                         {
  335.                                 lamp = ~lamp;
  336.                                 lamp1 = ~lamp1;
  337.                                 if(1==lamp)
  338.                                 y[10]='k';
  339.                                 else
  340.                                 y[10]='g';                                
  341.                                 upwm=1;
  342.                                 uart();
  343.                         }
  344.                         if(1 == upwm && 255 ==lamp1 )
  345.                         {
  346.                            pwm++;
  347.                            if(pwm>115)
  348.                            pwm=115;
  349.                            y[11]=pwm;
  350.                            flag_b=1;
  351.                            uart();
  352.                         }
  353.                         if(2 == upwm && 255 ==lamp1)
  354.                         {
  355.                            pwm--;
  356.                            if(pwm<15)
  357.                            pwm=15;
  358.                            y[11]=pwm;
  359.                            flag_b=2;
  360.                            uart();
  361.                         }                                            
  362.         }
  363.                 flagpwm++;
  364.                 if(0 == Cont && 1==flag_b && upwm!=0)
  365.                  upwm=2;
  366.                 if(0 == Cont && 2==flag_b && upwm!=0)
  367.                  upwm=1;
  368.                 if(0 == Cont && flagpwm>20)
  369.                 {
  370.                   flagpwm=0;
  371.                   upwm=0;
  372.                 }
  373.                                                       
  374. }            

  375. void LcdDisplay(int temp)          //lcd显示
  376. {

  377.         
  378.          if(temp< 0)                                //当温度值为负数
  379.           {

  380.                 //因为读取的温度是实际温度的补码,所以减1,再取反求出原码
  381.                 y[12]=45;
  382.                 temp=temp-1;
  383.                 temp=~temp;
  384.                 tp=temp;
  385.                 temp=tp*0.0625*100+0.5;        
  386.                 //留两个小数点就*100,+0.5是四舍五入,因为C语言浮点数转换为整型的时候把小数点
  387.                 //后面的数自动去掉,不管是否大于0.5,而+0.5之后大于0.5的就是进1了,小于0.5的就
  388.                 //算由?.5,还是在小数点后面。

  389.           }
  390.          else
  391.           {                        

  392.                 y[12]=43;
  393.                 tp=temp;//因为数据处理有小数点所以将温度赋给一个浮点型变量
  394.                 //如果温度是正的那么,那么正数的原码就是补码它本身
  395.                 temp=tp*0.0625*100+0.5;        
  396.                 //留两个小数点就*100,+0.5是四舍五入,因为C语言浮点数转换为整型的时候把小数点
  397.                 //后面的数自动去掉,不管是否大于0.5,而+0.5之后大于0.5的就是进1了,小于0.5的就
  398.                 //算加上0.5,还是在小数点后面。
  399.         }
  400.         y[13]='0'+temp / 10000;
  401.         y[14]='0'+ temp % 10000 / 1000;
  402.         y[15]='0'+temp % 1000 / 100;
  403.         y[16]='0'+temp % 100 / 10;
  404.          y[17]='0'+temp % 10;
  405. }

  406. #ifndef __TEMP_H_
  407. #define __TEMP_H_

  408. #include<reg51.h>
  409. //---重定义关键词---//
  410. #ifndef uchar
  411. #define uchar unsigned char
  412. #endif

  413. #ifndef uint
  414. #define uint unsigned int
  415. #endif

  416. //--定义使用的IO口--//
  417. sbit DSPORT=P3^7;

  418. //--声明全局函数--//
  419. void Delay1ms(uint );
  420. uchar Ds18b20Init();
  421. void Ds18b20WriteByte(uchar com);
  422. uchar Ds18b20ReadByte();
  423. void  Ds18b20ChangTemp();
  424. void  Ds18b20ReadTempCom();
  425. int Ds18b20ReadTemp();

  426. #endif

  427. #include"temp.h"
  428. /*******************************************************************************
  429. * 函 数 名         : Delay1ms
  430. * 函数功能                   : 延时函数
  431. * 输    入         : 无
  432. * 输    出         : 无
  433. *******************************************************************************/

  434. void Delay1ms(uint y)
  435. {
  436.         uint x;
  437.         for( ; y>0; y--)
  438.         {
  439.                 for(x=110; x>0; x--);
  440.         }
  441. }
  442. /*******************************************************************************
  443. * 函 数 名         : Ds18b20Init
  444. * 函数功能                   : 初始化
  445. * 输    入         : 无
  446. * 输    出         : 初始化成功返回1,失败返回0
  447. *******************************************************************************/

  448. uchar Ds18b20Init()
  449. {
  450.         uchar i;
  451.         DSPORT = 0;                         //将总线拉低480us~960us
  452.         i = 70;        
  453.         while(i--);         //延时642us
  454.         DSPORT = 1;                        //然后拉高总线,如果DS18B20做出反应会将在15us~60us后总线拉低
  455.         i = 0;
  456.         while(DSPORT)        //等待DS18B20拉低总线
  457.         {
  458.                 i++;
  459.                 if(i>5)//等待>5MS
  460.                 {
  461.                         return 0;//初始化失败
  462.                 }
  463.                 Delay1ms(1);        
  464.         }
  465.         return 1;//初始化成功
  466. }

  467. /*******************************************************************************
  468. * 函 数 名         : Ds18b20WriteByte
  469. * 函数功能                   : 向18B20写入一个字节
  470. * 输    入         : com
  471. * 输    出         : 无
  472. *******************************************************************************/

  473. void Ds18b20WriteByte(uchar dat)
  474. {
  475.         uint i, j;

  476.         for(j=0; j<8; j++)
  477.         {
  478.                 DSPORT = 0;                       //每写入一位数据之前先把总线拉低1us
  479.                 i++;
  480.                 DSPORT = dat & 0x01;  //然后写入一个数据,从最低位开始
  481.                 i=6;
  482.                 while(i--); //延时68us,持续时间最少60us
  483.                 DSPORT = 1;        //然后释放总线,至少1us给总线恢复时间才能接着写入第二个数值
  484.                 dat >>= 1;
  485.         }
  486. }
  487. /*******************************************************************************
  488. * 函 数 名         : Ds18b20ReadByte
  489. * 函数功能                   : 读取一个字节
  490. * 输    入         : com
  491. * 输    出         : 无
  492. *******************************************************************************/


  493. uchar Ds18b20ReadByte()
  494. {
  495.         uchar byte, bi;
  496.         uint i, j;        
  497.         for(j=8; j>0; j--)
  498.         {
  499.                 DSPORT = 0;//先将总线拉低1us
  500.                 i++;
  501.                 DSPORT = 1;//然后释放总线
  502.                 i++;
  503.                 i++;//延时6us等待数据稳定
  504.                 bi = DSPORT;         //读取数据,从最低位开始读取
  505.                 /*将byte左移一位,然后与上右移7位后的bi,注意移动之后移掉那位补0。*/
  506.                 byte = (byte >> 1) | (bi << 7);                                                  
  507.                 i = 4;                //读取完之后等待48us再接着读取下一个数
  508.                 while(i--);
  509.         }                                
  510.         return byte;
  511. }
  512. /*******************************************************************************
  513. * 函 数 名         : Ds18b20ChangTemp
  514. * 函数功能                   : 让18b20开始转换温度
  515. * 输    入         : com
  516. * 输    出         : 无
  517. *******************************************************************************/

  518. void  Ds18b20ChangTemp()
  519. {
  520.         Ds18b20Init();
  521.         Delay1ms(1);
  522.         Ds18b20WriteByte(0xcc);                //跳过ROM操作命令                 
  523.         Ds18b20WriteByte(0x44);            //温度转换命令
  524.         Delay1ms(100);        //等待转换成功,而如果你是一直刷着的话,就不用这个延时了

  525. }
  526. /*******************************************************************************
  527. * 函 数 名         : Ds18b20ReadTempCom
  528. * 函数功能                   : 发送读取温度命令
  529. * 输    入         : com
  530. * 输    出         : 无
  531. *******************************************************************************/

  532. void  Ds18b20ReadTempCom()
  533. {        

  534.         Ds18b20Init();
  535.         Delay1ms(1);
  536.         Ds18b20WriteByte(0xcc);         //跳过ROM操作命令
  537.         Ds18b20WriteByte(0xbe);         //发送读取温度命令
  538. }
  539. /*******************************************************************************
  540. * 函 数 名         : Ds18b20ReadTemp
  541. * 函数功能                   : 读取温度
  542. * 输    入         : com
  543. * 输    出         : 无
  544. *******************************************************************************/

  545. int Ds18b20ReadTemp()
  546. {
  547.         int temp = 0;
  548.         uchar tmh, tml;
  549.         Ds18b20ChangTemp();                                 //先写入转换命令
  550.         Ds18b20ReadTempCom();                        //然后等待转换完后发送读取温度命令
  551.         tml = Ds18b20ReadByte();                //读取温度值共16位,先读低字节
  552.         tmh = Ds18b20ReadByte();                //再读高字节
  553.         temp = tmh;
  554.         temp <<= 8;
  555.         temp |= tml;
  556.         return temp;
  557. }
复制代码



捕获.JPG
捕获1.JPG

程序 - 副本1.5.rar

338.56 KB, 下载次数: 4

回复

使用道具 举报

ID:420836 发表于 2021-2-8 08:27 | 显示全部楼层
当PWM开启时,定时器中断会扰乱18B20的延迟。
回复

使用道具 举报

ID:115204 发表于 2021-2-8 08:43 | 显示全部楼层
有可能是你在Ds18b20ReadByte函数里总线释放的时间有些短,适当添加一点延时再试试,就是i++那里
回复

使用道具 举报

ID:871393 发表于 2021-2-8 09:06 | 显示全部楼层
我用hx711时, 发现负数的移位有可能得出错误结果(估计是编译器有差异), 使用一般加减乘除试试
回复

使用道具 举报

ID:373388 发表于 2021-2-8 10:39 | 显示全部楼层
18b20在读写时,时序比较严格,中断以后基本上都会打乱时序,读数错误,利用crc校验, 验证数据,如果数据不正确,重新读数;
回复

使用道具 举报

ID:373388 发表于 2021-2-8 13:07 | 显示全部楼层
上传一个ds18b20的crc校验程序,供参考。 crc8.rar (1.03 KB, 下载次数: 8)
回复

使用道具 举报

ID:290576 发表于 2021-2-8 15:15 | 显示全部楼层
justinchill 发表于 2021-2-8 08:43
有可能是你在Ds18b20ReadByte函数里总线释放的时间有些短,适当添加一点延时再试试,就是i++那里

加上两个空指令后 直接就错了
回复

使用道具 举报

ID:290576 发表于 2021-2-8 15:16 | 显示全部楼层
xhaity 发表于 2021-2-8 13:07
上传一个ds18b20的crc校验程序,供参考。

文件错误
回复

使用道具 举报

ID:213173 发表于 2021-2-8 17:44 | 显示全部楼层
如果只是为了调灯的亮度,没必要设置这么高频率的PWM,中断里运行的语句越少越好。否则会破坏18b20读写时序而出错。串口通讯也要把中断方式改查询方式为好。
回复

使用道具 举报

ID:390416 发表于 2021-2-8 18:48 | 显示全部楼层
你这个代码居然有死等几百us  ,去看看我们 人人学会单片机的代码
http://www.51hei.com/bbs/dpj-200968-1.html
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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