找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1702|回复: 1
收起左侧

单片机测温程序中的数组、串口问题 求大神帮忙

[复制链接]
ID:269536 发表于 2018-2-1 16:57 | 显示全部楼层 |阅读模式
10黑币
求大神帮忙,
这一个单片机多路测温,然后串口传入PC
这个串口通过数组传入一直些不好了,求好心人指点,程序在下方
测温程序
  1. #include <reg52.h>
  2. #include <intrins.h>


  3. #define MAXNUM 8 //定义最多有8个 DS18B20

  4. sbit DQ=P2^3;    //定义DS18B20数据线

  5. sbit RS=P2^6;     //液晶端口控制线端口定义
  6. sbit RW=P2^5;     //液晶端口控制线端口定义
  7. sbit E= P2^7;     //液晶端口控制线端口定义

  8. sbit keyenter =P3^2;
  9. sbit keyup    =P3^3;
  10. sbit keydown  =P3^4;

  11. sbit led=    P1^6;
  12. sbit buzzer= P1^7;



  13. unsigned char code lcd0[]={"SEARCH ROMING..."};
  14. unsigned char code lcd1[]={"SEARCH ROM OK!"};
  15. unsigned char code lcd2[]={"The total is:"};
  16. unsigned char code lcd3[]={"No.( ):"};
  17. unsigned char code lcd4[]={'0','1','2','3','4','5','6','7','8','9','.',0xdf,0x43,' '};
  18. unsigned char code setinfo[]={"Set Alarm Point:"};
  19. unsigned char code pointinfo[]={"Alarm:"};
  20. signed char tempalarm=0;


  21. //0xdf在1602中是“℃”符号的左上角那个圆,0X43是大写的"C" 他们一起构成了”℃“这个符号

  22. unsigned char dat[6];//用来显示温度的参数                     
  23. unsigned char temp_l,temp_h,negetiveflag=0,temp_over,t;
  24. unsigned char num=0;
  25. unsigned int i;
  26. bit keyflag=0;
  27. idata unsigned char al[MAXNUM];
  28. idata unsigned char ID[MAXNUM][8];

  29. signed char alarm=30; //默认为30摄氏度报警

  30. /***********************液晶模块**********************************/
  31. void delaylcd(void)//延时程序
  32. {
  33.     unsigned char y;
  34.     for(y=0;y<250;y++);
  35. }

  36. void LCD_write_com(unsigned char com)//液晶写命令函数
  37. {
  38.     delaylcd();
  39.     RS=0; //RS为1 写命令
  40.     RW=0;
  41.     E=0;
  42.     E=1;
  43.     P0=com;
  44.        E=0;
  45.     delaylcd();
  46. }

  47. void LCD_write_data(unsigned char dat)//液晶写数据函数
  48. {
  49.     delaylcd();
  50.     RS=1;   //RS为1 写数据
  51.     RW=0;
  52.     E=0;
  53.     E=1;
  54.     P0=dat;
  55.     E=0;
  56.     delaylcd();
  57. }
  58. void lcdinit(void)//初始化
  59. {
  60.     LCD_write_com(0x01); //液晶清屏 
  61.     LCD_write_com(0x38); //1602”功能设置命令字“ 显示2行 每行字体用5*8 ASCII显示    8位数据接口
  62.     LCD_write_com(0x0c); //显示控制,开始显示,不显示游标,游标不闪烁   
  63.     LCD_write_com(0x06); //输入方式为增量输入,不移屏幕
  64. }

  65. /************************ds18b20****************************/
  66. void delay_nus(unsigned int n)//延时 程序 一次8+6(进出)=14us
  67. {
  68.     while(n--);
  69. }

  70. void reset(void)  //ds18b20初始化复位操作
  71. {
  72.      unsigned char x=0;
  73.      DQ = 1;              //DQ复位
  74.      delay_nus(8);      //稍做延时
  75.      DQ = 0;              //单片机将DQ拉低
  76.      delay_nus(80);     //精确延时 大于 480us
  77.      DQ = 1;              //拉高总线
  78.      delay_nus(10);
  79.      x=DQ;                //稍做延时后 如果x=0则初始化成功 x=1则初始化失败
  80.      delay_nus(5);
  81. }

  82. void write_bit(unsigned char dat)    //DS18B20 写一位 操作
  83. {
  84.       DQ = 0;
  85.     _nop_();
  86.     _nop_();
  87.      DQ = dat&0x01;
  88.     delay_nus(5);
  89.      DQ = 1;
  90. }

  91. void write_byte(unsigned char dat)//写一个字节
  92. {
  93.      unsigned char i,j;
  94.      for (i=8; i>0; i--)
  95.      {
  96.         j=dat&0x01;
  97.           write_bit(j);
  98.         dat>>=1;
  99.     }
  100. }

  101. unsigned char read_2bit(void)//读二位 子程序
  102. {
  103.     unsigned char i;
  104.     unsigned char dat = 0;
  105.     for (i=2;i>0;i--)
  106.     {
  107.         DQ = 0; // 给脉冲信号
  108.         dat<<=1;
  109.         DQ = 1; // 给脉冲信号
  110.         if(DQ)
  111.         dat|=0x01;
  112.         delay_nus(4);
  113.     }
  114.      return(dat);
  115. }

  116. unsigned char read_byte(void)//读一个字节 子程序
  117. {
  118.     unsigned char i=0;
  119.     unsigned char dat = 0;
  120.     for (i=8;i>0;i--)
  121.     {
  122.         DQ = 0; // 给脉冲信号
  123.         dat>>=1;
  124.         DQ = 1; // 给脉冲信号
  125.         if(DQ)
  126.         dat|=0x80;
  127.         delay_nus(4);
  128.     }
  129.      return(dat);  
  130. }



  131. void delay_nms(unsigned int n)
  132. {
  133.     unsigned int j=0;
  134.     unsigned char i=0;
  135.     for(j=0;j<n;j++)
  136.     {
  137.         for(i=0;i<120;i++)
  138.         {
  139.             _nop_();
  140.         }
  141.     }
  142. }

  143. void read_temp(unsigned char num_data)//读取温度 子程序 参数表示读第几个传感器
  144. {
  145.     unsigned char f;   
  146.     reset();
  147.     write_byte(0xcc);//发送跳过ROM号命令
  148.     write_byte(0x44);//发送温度转换命令
  149.     delay_nms(2000);        
  150.     reset();
  151.     write_byte(0x55);//发送匹配ROM号命令
  152.     for(f=0;f<8;f++) //8字节ROM号
  153.     {
  154.         write_byte(ID[num_data][f]);//发匹配ROM
  155.     }
  156.     delay_nus(100);
  157.     write_byte(0xbe);//读寄存器命令
  158.     delay_nus(100);
  159.     temp_l=read_byte();
  160.     temp_h=read_byte();
  161. }


  162. void temp_convert(void)//温度转换
  163. {
  164.     negetiveflag=0;
  165.     negetiveflag=temp_h&0x80;
  166.     if(negetiveflag)
  167.     {
  168.         negetiveflag=1;
  169.         temp_h=~temp_h;
  170.           if(temp_l==0)
  171.         {
  172.              temp_h++;  //若低8位全为0且温度为负,取补时就要向高位进1
  173.         }
  174.           temp_l=~temp_l+1;
  175.     }
  176.     temp_h<<=4;
  177.     temp_l>>=4;
  178.     temp_over=temp_h|temp_l;
  179.     tempalarm=temp_over;
  180.     if(negetiveflag==1)
  181.     {
  182.          tempalarm=tempalarm*(-1);
  183.     }
  184. }

  185. /*******************显示***************************/
  186. void search_cartoon(void)//搜索ROM动画
  187. {
  188.     lcdinit();
  189.     LCD_write_com(0x80);//液晶第一行地址
  190.     for(i=0;i<16;i++)
  191.     {
  192.         LCD_write_data(lcd0[i]);
  193.     }
  194.     LCD_write_com(0xc0);//液晶第二行地址
  195.     for(i=0;i<16;i++)
  196.     {
  197.         LCD_write_data(0xff);//显示类似进度条的黑点
  198.         delay_nms(num*80);
  199.     }         
  200. }

  201. void display_alarm_normal(signed char alarm_data)//显示报警温度
  202. {
  203.     unsigned int data_b,data_temp,l,datx[6]={0};
  204.     data_b=alarm_data;
  205.     negetiveflag=0;

  206.     LCD_write_com(0x80);
  207.     for(l=0;l<6;l++)
  208.     {
  209.         LCD_write_data(pointinfo[l]);
  210.     }   

  211.     if(alarm_data>=0)
  212.     {
  213.         data_b=alarm_data/100;//百位//
  214.     }
  215.     else
  216.     {
  217.         negetiveflag=1;
  218.         alarm_data=alarm_data*(-1);//变成正温度
  219.     }

  220.     data_temp=alarm_data%100;//对100取余,也就是十位数和个位数

  221.     datx[0]=data_temp/10;//十位
  222.     datx[1]=data_temp%10;//个位
  223.     datx[2]=13;//空格符号
  224.     datx[3]=13;//空格符号
  225.     datx[4]=11;//摄氏度符号
  226.     datx[5]=12;//摄氏度符号

  227.     LCD_write_com(0x88);

  228.     if(negetiveflag==1)
  229.     {
  230.         LCD_write_data(0x2d);//显示"-"  “负号”
  231.     }
  232.     else
  233.     {
  234.         LCD_write_data(lcd4[data_b]);//如果大于0就显示百位数,否则百位数就显示“负号”
  235.     }

  236.     for(l=0;l<6;l++)//显示报警值和摄氏度符号
  237.     {
  238.       LCD_write_data(lcd4[datx[l]]);
  239.     }   
  240. }

  241. void display_total(void)      //显示搜索到的DS18B20传感器数目
  242. {
  243.     lcdinit();
  244.     LCD_write_com(0x80);//第一行地址
  245.     for(i=0;i<14;i++)
  246.     {
  247.         LCD_write_data(lcd1[i]);
  248.     }
  249.     LCD_write_com(0xc0);//第二行地址
  250.     for(i=0;i<13;i++)
  251.     {
  252.         LCD_write_data(lcd2[i]);
  253.     }
  254.     LCD_write_data(lcd4[num]);
  255.     delay_nms(2000);
  256.     lcdinit();                    //清屏,准备显示温度
  257.     display_alarm_normal(alarm);//显示报警温度
  258. }



  259. void display_ds18b20(i)//显示编号为i的DS18B20的温度//
  260. {
  261.     unsigned int data_b,data_temp,l;
  262.     data_b=temp_over/1000;//百位//
  263.     data_temp=temp_over%100;
  264.     dat[0]=data_temp/10;//十位//
  265.     dat[1]=data_temp%10;//个位//
  266.     dat[2]=13; //空格
  267.     dat[3]=13; //空格
  268.     dat[4]=11; //摄氏度符号
  269.     dat[5]=12; //摄氏度符号

  270.     LCD_write_com(0xc0);
  271.     for(l=0;l<7;l++)
  272.     {
  273.         LCD_write_data(lcd3[l]);
  274.     }
  275.     LCD_write_com(0xc4);
  276.     LCD_write_data(lcd4[++i]);
  277.     LCD_write_com(0xc8);

  278.     if(negetiveflag==1)
  279.     {
  280.         LCD_write_data(0x2d);
  281.     }
  282.     else
  283.     {
  284.         LCD_write_data(lcd4[data_b]);
  285.     }

  286.     for(l=0;l<6;l++)
  287.         LCD_write_data(lcd4[dat[l]]);
  288.     delay_nms(1000);
  289. }




  290. void display_alarm(signed char alarm_data)//显示报警温度
  291. {
  292.     unsigned int data_b,data_temp,l;
  293.     data_b=alarm_data;
  294.     negetiveflag=0;
  295.     if(alarm_data>=0)
  296.     {
  297.      data_b=alarm_data/100;//百位//
  298.     }
  299.     else
  300.     {
  301.      negetiveflag=1;
  302.      alarm_data=alarm_data*(-1);//变成正温度
  303.     }

  304.     data_temp=alarm_data%100;//对100取余,也就是十位数和个位数

  305.     dat[0]=data_temp/10;//十位
  306.     dat[1]=data_temp%10;//个位
  307.     dat[2]=13;//空格符号
  308.     dat[3]=11;//摄氏度符号
  309.     dat[4]=12;//摄氏度符号

  310.     if(keyflag==1)//刚刚进入设置报警温度
  311.     {
  312.         lcdinit();
  313.         LCD_write_com(0x80);//第一行地址
  314.         for(l=0;l<16;l++)
  315.         {
  316.             LCD_write_data(setinfo[l]);
  317.         }
  318.    
  319.         LCD_write_com(0xc0);//第二行地址
  320.         for(l=0;l<8;l++)
  321.         {
  322.             LCD_write_data(pointinfo[l]);
  323.         }
  324.     }
  325.    

  326.     LCD_write_com(0xc7);

  327.     if(negetiveflag==1)
  328.     {
  329.         LCD_write_data(0x2d);//显示"-"  “负号”
  330.     }
  331.     else
  332.     {
  333.         LCD_write_data(lcd4[data_b]);//如果大于0就显示百位数,否则百位数就显示“负号”
  334.     }

  335.     for(l=0;l<5;l++)//显示报警值和摄氏度符号
  336.     {
  337.       LCD_write_data(lcd4[dat[l]]);
  338.     }   
  339. }


  340. /***********************自动搜索ROM*****************************/
  341. void search_rom(void)//搜索ROM
  342. {
  343.     unsigned char k=0,l=0,chongtuwei=0,m=0,n=0;
  344.     unsigned char s=0;
  345.     unsigned char zhan[MAXNUM];
  346.     unsigned char ss[64];
  347.     do
  348.     {
  349.         reset();
  350.         write_byte(0xf0);  //搜索ROM命令   
  351.         for(m=0;m<8;m++)
  352.         {
  353.             for(n=0;n<8;n++)
  354.             {
  355.                 k=read_2bit();//读两位数据
  356.                 k=k&0x03;   
  357.                 s>>=1;
  358.                 if(k==0x01)//01读到的数据为0 写0 此位为0的器件响应
  359.                 {           
  360.                     write_bit (0);
  361.                     ss[(m*8+n)]=0;
  362.                 }
  363.                 else if(k==0x02)//读到的数据为1 写1 此位为1的器件响应
  364.                 {
  365.                     s=s|0x80;
  366.                     write_bit (1);
  367.                     ss[(m*8+n)]=1;
  368.                 }
  369.                 else if(k==0x00)//读到的数据为0  有冲突位 判断冲突位
  370.                 {                //如果冲突位大于栈顶写0 小于栈顶写以前数据 等于栈顶写1
  371.                     chongtuwei=m*8+n+1;                    
  372.                     if(chongtuwei>zhan[l])
  373.                     {                        
  374.                         write_bit (0);
  375.                         ss[(m*8+n)]=0;                                                
  376.                         zhan[++l]=chongtuwei;                        
  377.                     }
  378.                     else if(chongtuwei<zhan[l])
  379.                     {
  380.                         s=s|((ss[(m*8+n)]&0x01)<<7);
  381.                         write_bit (ss[(m*8+n)]);
  382.                     }
  383.                     else if(chongtuwei==zhan[l])
  384.                     {
  385.                         s=s|0x80;
  386.                         write_bit (1);
  387.                         ss[(m*8+n)]=1;
  388.                         l=l-1;
  389.                     }
  390.                 }
  391.                 else
  392.                 {
  393.                     goto loop;
  394.                 }
  395.             }
  396.             ID[num][m]=s;        
  397.         }
  398.         num++;
  399.     }
  400.     while(zhan[l]!=0&&(num<MAXNUM));        
  401. loop:
  402.     search_cartoon();
  403.     display_total();

  404. }



  405. void main (void)
  406. {
  407.     unsigned char i=0,t=0;
  408.     delay_nms(50);
  409.     IT0=0;
  410.     EX0=1;
  411.     EA=1;

  412.     search_rom();//搜索ROM并且存储,把18B20的每一个ROM读取出来,方便下次调用


  413.     reset();
  414.         
  415.     while(1)
  416.     {
  417.         if(keyflag==0)
  418.         {
  419.               for(i=0;i<num;i++)    //每一个 ds18b20 循环显示
  420.               {
  421.                     if(keyflag==1) break;
  422.                     read_temp(i);   //读编号 i 的ds18b20 的温度
  423.                     if(keyflag==1) break;
  424.                     temp_convert(); //调用温度转换
  425.                     if(keyflag==1) break;
  426.                     if(tempalarm>alarm)//报警判断
  427.                     {
  428.                       for(t=0;t<3;t++)
  429.                       {
  430.                            buzzer=0;//打开报警蜂鸣器
  431.                          led=0;   //打开报警指示灯
  432.                          delay_nms(100);
  433.                          buzzer=1;//关闭报警蜂鸣器
  434.                          led=1;   //关闭报警指示灯
  435.                          delay_nms(100);
  436.                       }
  437.                     }
  438.                     display_ds18b20(i);//显示 编号 i 的温度        
  439.               }
  440.         }         

  441.         else//设置按键按下 进行按键扫描动作
  442.         {
  443.            display_alarm(alarm);
  444.            keyflag=0;
  445.            while(1)
  446.            {
  447.                 if(keyenter==0&&keyflag==0)//进入设置以后,再按设置按键,就退出设置,重新显示每一个通道温度
  448.                 {
  449.                   delay_nms(200);
  450.                   if(keyenter==0)
  451.                   {
  452.                     while(keyenter==0);     
  453.                     lcdinit();
  454.                     display_alarm_normal(alarm);//显示报警温度
  455.                     break;//退出按键扫描
  456.                   }
  457.                 }
  458.             if(keyup==0)//
  459.                 {
  460.                   delay_nms(200);
  461.                   if(keyup==0&&alarm<125)
  462.                   {
  463.                      alarm++;//报警温度加1
  464.                   }
  465.                   display_alarm(alarm);
  466.                 }
  467.            if(keydown==0&&alarm>-55)//
  468.                 {
  469.                   delay_nms(200);
  470.                   if(keydown==0)
  471.                   {
  472.                     alarm--;//报警温度减1
  473.                   }
  474.                   display_alarm(alarm);
  475.                 }
  476.                 delay_nms(50);
  477.            }
  478.            EX0=1;   
  479.         }
  480.                   
  481.     }//while(1)结束  
  482. }

  483. void key_init0(void) interrupt 0
  484. {
  485.     if(keyenter==0)
  486.     {
  487.       delay_nms(10);
  488.       if(keyenter==0)
  489.       {
  490.           EX0=0;
  491.         keyflag=1;
  492.       }
  493.     }
  494.    
  495. }


  496. 串口程序
  497. //#include <STC89C5xRC.H>
  498. #include "reg52.h"             //此文件中定义了单片机的一些特殊功能寄存器
  499. typedef unsigned int u16;      //对数据类型进行声明定义
  500. typedef unsigned char u8;

  501. sbit led=P2^0;     //定义P20口是led
  502. unsigned char code darArr1[]={"*23 75 798 5 0.3 89 &"};    //串口发送内容
  503. void UART_init(void)
  504. {
  505.     TMOD = 0x20;
  506.     SCON = 0x40;
  507.     TH1 = 0xF3;
  508.     TL1 = TH1;
  509.     PCON = 0x80;
  510.     TR1 = 1;
  511. }

  512. /*******************************************************************************
  513. * 函 数 名         : Timer0Init
  514. * 函数功能           : 定时器0初始化
  515. * 输    入         : 无
  516. * 输    出         : 无
  517. *******************************************************************************/
  518. void Timer0Init()
  519. {
  520.     TMOD|=0X01;//选择为定时器0模式,工作方式1,仅用TR0打开启动。

  521.     TH0=0XFC;    //给定时器赋初值,定时1ms
  522.     TL0=0X18;   
  523.     ET0=1;//打开定时器0中断允许
  524.     EA=1;//打开总中断
  525.     TR0=1;//打开定时器            
  526. }
  527. void UART_send_byte(unsigned char dat)
  528. {
  529.     SBUF = dat;
  530.     while(!TI);
  531.     TI = 0;
  532. }
  533. void main(){

  534. unsigned char i=0;
  535.     UART_init();
  536.     P1=0xf0;
  537.     Timer0Init();  //定时器0初始化
  538.     while(1){

  539.     }

  540. }

  541. /*******************************************************************************
  542. * 函 数 名         : void Timer0() interrupt 1
  543. * 函数功能           : 定时器0中断函数
  544. * 输    入         : 无
  545. * 输    出         : 无
  546. *******************************************************************************/
  547. void Timer0() interrupt 1
  548. {
  549.     static u16 i;
  550.     TH0=0XFC;    //给定时器赋初值,定时1ms
  551.     TL0=0X18;
  552.     i++;
  553.     if(i==1000)
  554.     {
  555.         i=0;
  556.         led=~led;
  557.         for(i=0;darArr1[i]!='&';i++){
  558.             UART_send_byte(darArr1[i]);
  559.         }   
  560.     }   
  561. }
复制代码


AAA.zip

302.88 KB, 下载次数: 3

回复

使用道具 举报

ID:284230 发表于 2018-2-16 22:10 | 显示全部楼层
不要在中断里处理串口发送这种很耗时的处理。移到主程序中去。或使用中断方式写串口发送程序。

评分

参与人数 1黑币 +20 收起 理由
admin + 20 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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