调试AT89S52 ——MLX90614 失败,求助

2020-01-21 21:42发布

这几天调试AT89S52 ——MLX90614 ,一直无应答。是移植IIC过来的,不知道为啥老是无应答。
参考了http://www.ourdev.cn/forum.php?mod=viewthread&tid=3990328  这个帖子 还是失败。
一直找不到原因,电路上我是用10K电阻上拉的。

代码如下:

  1. #include "reg52.h"
  2. #include <intrins.h>
  3. #include   <stdio.h>

  4. #define uchar unsigned char
  5. #define uint  unsigned int
  6. //************函数声明*****************************************************
  7. void start();  //MLX90614发起始位子程序
  8. void stop();  //MLX90614发结束位子程序
  9. uchar ReadByte(void);  //MLX90614接收字节子程序
  10. //void send_bit(void);  //MLX90614发送位子程序
  11. void SendByte(uchar number);  //MLX90614接收字节子程序
  12. void read_bit(void);  //MLX90614接收位子程序
  13. void delay(uint N);  //延时程序
  14. uint readtemp(void);  //读温度数据
  15. void init1602(void);  //LCD初始化子程序
  16. void busy(void);  //LCD判断忙子程序
  17. void delayscan(i);

  18. //************数据定义****************************************************
  19. bdata uchar flag1; //可位寻址数据
  20. sbit bit_out=flag1^7;
  21. sbit bit_in=flag1^0;

  22. sbit SCK=P1^7;
  23. sbit SDA=P1^6;
  24. //i2c总线
  25. //sbit scl = P2^2;
  26. //sbit sda = P2^3;
  27. sbit SCL=P1^7;

  28. uchar tempH,tempL,err;
  29. //**************************  mlx90614  ***********************************
  30. //command mode  命令模式
  31. #define RamAccess 0x00 //对RAM操作
  32. #define EepomAccess 0x20 //对EEPRAM操作
  33. #define Mode 0x60 //进入命令模式
  34. #define ExitMode 0x61 //退出命令模式
  35. #define ReadFlag 0xf0 //读标志
  36. #define EnterSleep 0xff //进入睡眠模式
  37. //ram address read only RAM地址(只读)
  38. #define AbmientTempAddr 0x03 //周围温度
  39. #define IR1Addr 0x04
  40. #define IR2Addr 0x05
  41. #define LineAbmientTempAddr 0x06   //环境温度
  42. /*0x0000 0x4074  16500  0.01/单元
  43.      -40    125*/
  44. #define LineObj1TempAddr 0x07 //目标温度,红外温度
  45. /*0x27ad-0x7fff  0x3559 22610 0.02/单元
  46.   -70.01-382.19  0.01   452.2*/
  47. #define LineObj2TempAddr 0x08
  48. //eepom address  EEPROM地址
  49. #define TObjMaxAddr 0x00 //测量范围上限设定
  50. #define TObjMinAddr 0x01 //测量范围下限设定
  51. #define PWMCtrlAddr 0x02 //PWM设定
  52. #define TaRangeAddr 0x03 //环境温度设定
  53. #define KeAddr 0x04 //频率修正系数
  54. #define ConfigAddr 0x05 //配置寄存器
  55. #define SMbusAddr 0x0e //器件地址设定
  56. #define Reserverd1Addr 0x0f //保留
  57. #define Reserverd2Addr 0x19 //保留
  58. #define ID1Addr 0x1c //ID地址1
  59. #define ID2Addr 0x1d //ID地址2
  60. #define ID3Addr 0x1e //ID地址3
  61. #define ID4Addr 0x1f //ID地址4


  62. #define _Nop()   _nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_()
  63. #define delayNOP();  { _nop_();_nop_();_nop_();_nop_();_nop_();};// _nop()_=1 CPU cycle

  64. typedef bit BOOL  ;
  65. uchar CHACK;
  66. uchar aa;
  67. #define Nack_number 10

  68. bit ack;
  69. sbit rs = P2^6 ;
  70. sbit rw = P3^6 ;
  71. sbit ep = P2^7 ;



  72. void delayms(uchar) ;
  73. void lcd_wcmd(uchar) ;
  74. BOOL lcd_bz() ;
  75. void lcd_pos(uchar) ;
  76. void lcd_wdat(uchar) ;
  77. void display(uchar,uchar *) ;
  78. union
  79. {         
  80.   uchar c[2];          //c[0]为X的高位,c[1]为X的底位,
  81.            int x;
  82. }Temp;

  83. uchar  dis1[16]  ;
  84. uchar  dis2[16] ;

  85. /*void delay2ms()
  86. {
  87.         byte i;
  88.         for(i=0xff;i!=0;i--)
  89.                 {Wdt();} //4*1.085*256
  90. }

  91. void delay2(void)
  92. {
  93.         byte i;
  94.         for(i=2;i!=0;i--);
  95. }
  96.           */


  97. void longdelay(uchar s)  //长延时
  98. {
  99.          while(s--)
  100.          {
  101.                   delayms(60) ;
  102.          }
  103. }

  104. void delayms(uchar ms)
  105. {       // 延时子程序
  106.          uchar i ;
  107.          while(ms--)
  108.          {
  109.                   for(i = 0 ; i<250;i++) ;
  110.          }
  111. }

  112. void delay_nus(unsigned int n)       //N us延时函数
  113.   {
  114.    unsigned int i=0;
  115.    for (i=0;i<n;i++)
  116.    _nop_();
  117.   }

  118. BOOL lcd_bz()
  119. {       // 测试LCD忙碌状态
  120.          BOOL result ;
  121.          rs = 0 ;
  122.          rw = 1 ;
  123.          ep = 1 ;
  124.          result = (BOOL)(P0 & 0x80) ;
  125.          ep = 0 ;
  126.          return result ;
  127. }

  128. void lcd_wcmd(uchar cmd)
  129. {       // 写入指令数据到LCD
  130.         while(lcd_bz()) ;
  131.         rs = 0 ;
  132.         rw = 0 ;
  133.         ep = 0 ;
  134.         P0 = cmd ;
  135.         ep = 1 ;
  136.         ep = 0 ;  
  137. }

  138. void lcd_pos(uchar pos)
  139. {       //设定显示位置
  140.         lcd_wcmd(pos | 0x80) ;
  141. }

  142. void lcd_wdat(uchar dat)
  143. {       //写入字符显示数据到LCD
  144.         while(lcd_bz()) ;
  145.           rs = 1 ;
  146.           rw = 0 ;
  147.           ep = 0 ;
  148.           P0 = dat ;
  149.           ep = 1 ;
  150.           ep = 0 ;
  151. }

  152. void lcd_init()
  153. {       //LCD初始化设定
  154.          lcd_wcmd(0x38) ;   //function set
  155.          delayms(1) ;
  156.          lcd_wcmd(0x38) ;   //function set
  157.          delayms(1) ;
  158.          lcd_wcmd(0x08) ;   //display on/off
  159.          delayms(1) ;
  160.          lcd_wcmd(0x01) ;   //清除LCD的显示内容
  161.          delayms(1) ;
  162.          lcd_wcmd(0x06) ;   //entry mode set
  163.          delayms(1) ;
  164.          lcd_wcmd(0x0F) ;   //entry mode set
  165.          delayms(1) ;
  166. }

  167. /*---------------
  168. 函数名称:display()
  169. 功能 :在LCD上显示数组的数据
  170. 说明 :先写显示地址,后写显示数据
  171. 调用 :lcd_wcmd(), lcd_pos()
  172. 入口参数:pos 写入的位置,q指向要写入的数据所在的数组
  173. 返回值 :无
  174. ----------------*/
  175. void display(uchar pos, uchar *q)
  176. {
  177.          uchar i ;
  178.          //lcd_wcmd(0x01) ; //clear
  179.          delayms(10) ;
  180.          lcd_pos(pos) ;
  181.          for(i=0 ;i<16;i++)
  182.          {
  183.                   lcd_wdat(*q) ;
  184.                   q++ ;
  185.                 //  longdelay(2) ;
  186.          }
  187. }

  188. void init_serial(void)
  189.                   
  190. {
  191.                                 //定时器1的工作方式2
  192.         TMOD=0x20;        //装载计数初值
  193.         TL1=0xfd;
  194.         TH1=0xfd;        //采用串口工作方式1,无奇偶校验
  195.         SCON=0x50;        //串口波特率不加倍
  196.         PCON=0x00;         //开总中断,开串口中断
  197.         IE=0x90;         //启动定时器1
  198.         TR1=1;
  199. }

  200.    void comsend(uchar ch)           //串口发送数据  发送一个数据
  201. {
  202. //        TB8=0;
  203.         SBUF = ch;
  204.     while(!TI);                         
  205.     TI=0;               
  206. }
  207. /*--------------------------------------------------------------------------
  208. 函数名: start_bit
  209. 功能: 在SMBus总线上产生起始状态
  210. 注解: 参考"系统管理总线说明书-版本2.0"
  211. --------------------------------------------------------------------------*/
  212. void start_bit()
  213. {
  214. //   _SDA_OUTPUT;                                    //设置SDA为输出
  215.    SDA=1;                                                //设置SDA线为高电平
  216.     //_nop_(); _nop_();                          
  217.    SCL=1;                                                //设置SCL线为高电平
  218.    delayNOP();                                        //在终止和起始状态之间产生总线空闲时间(Tbuf=4.7us最小值)
  219.    SDA=0;                                                //设置SDA线为低电平
  220.    delayNOP();  
  221.    //(重复)开始状态后的保持时间,在该时间后,产生第一个时钟信号    //Thd:sta=4us最小值                                                   
  222.    SCL=0;                                                //设置SCL线为低电平
  223.     //_nop_(); _nop_();
  224. }
  225. /*------------------------------------------------------------------------
  226. 函数名: stop_bit
  227. 功能: 在SMBus总线上产生终止状态
  228. 注解: 参考"系统管理总线说明书-版本2.0"
  229. ------------------------------------------------------------------------*/
  230. void stop_bit()
  231. {
  232. // _SDA_OUTPUT;                                         //设置SDA为输出

  233. SDA=0;
  234.         SCL=1;
  235.         delayNOP();                         //延时5us
  236.         SDA=1;
  237.         delayNOP();
  238.         SCL=0;                                    //终止状态建立时间(Tsu:sto=4.0us最小值)
  239.                                             //设置SDA线为高电平
  240. }
  241. /*-------------------------------------------------------------
  242. 函数名: send_bit
  243. 功能:在SMBus总线上发送一位数据
  244. //-------------------------------------------------------------*/
  245. void send_bit(unsigned char bit_out)
  246. {
  247.    
  248. //  _SDA_OUTPUT;                          //设置SDA为开漏输出以在总线上传送数据
  249.   if(bit_out==1)                  //核对字节的位
  250.           SDA=1;                      //如果bit_out=1,设置SDA线为高电平
  251.   else                                                         
  252.     SDA=0;                //如果bit_out=0,设置SDA线为低电平
  253. //delayNOP();                                    //
  254.   SCL=1;                      //设置SCL线为高电平
  255. delayNOP();                          //时钟脉冲高电平脉宽(10.6us)
  256.   SCL=0;                      //设置SCL线为低电平
  257.   delayNOP();      //时钟脉冲低电平脉宽  
  258. }
  259. /*------------------------------------------------------------
  260. 函数名: receive_bit
  261. 功能:在SMBus总线上接收一位数据
  262. //---------------------------------------------------------*/
  263. unsigned char receive_bit()
  264. {
  265.   unsigned char bit_in;
  266.   SDA=1;                                    //设置SDA为高阻输入
  267.   SCL=1;                                //设置SCL线为高电平
  268.   delay_nus(1);
  269.   if(SDA==1)                            //从总线上读取一位,赋给bit_in      
  270.        bit_in=1;
  271.   else
  272.        bit_in=0;
  273.   delay_nus(1);
  274.   SCL=0;                                  //设置SCL线为低电平                                          
  275.   delay_nus(2);
  276.   return bit_in;               //返回bit_in值
  277. }
  278. /*-----------------------------------------------------------
  279. 函数名: slave_ack
  280. 功能: 由受控器件MLX90614中读取确认位
  281. 返回值:  unsigned char ack
  282. 1 - ACK
  283. 0 - NACK
  284. //-----------------------------------------------------------*/
  285. unsigned char slave_ack()
  286. {
  287.    unsigned char ack;
  288.    ack=0;
  289.    SDA=1;                                    //设置SDA为高阻输入
  290.    SCL=1;                    //设置SCL线为高电平
  291.    delayNOP();  
  292.    if(SDA==1)                                    //从总线上读取一位,赋给ack
  293.          ack=0;
  294.    else
  295.          ack=1;
  296.    //delay_nus(1);
  297.    SCL=0;                   //设置SCL线为低电平
  298.   // delay_nus(2);
  299.    return ack;
  300. }
  301. /*--------------------------------------------------------
  302. 发送一个字节
  303. 函数名: TX_byte
  304. 功能: 在SMBus总线上发送一个字节
  305. 参数: unsigned char TX_buffer (将要在总线上发送的字节)
  306. 注解: 先发送字节的高位

  307. //--------------------------------------------------------*/
  308. void TX_byte(unsigned char TX_buffer)
  309. {
  310. unsigned char idata n = 8;
  311.         while(n--)
  312.         {
  313.                 if(0x80==(TX_buffer&0x80))
  314.                 {
  315.                         SDA = 1 ;           //传送 1
  316.                         SCL = 1 ;
  317.                         delayNOP();
  318.                         SCL = 0 ;
  319.                         SDA = 0 ;
  320.                        
  321.                 }
  322.                 else
  323.                 {
  324.                         SDA = 0;                 //传送 0
  325.                         SCL = 1;
  326.                         delayNOP();
  327.                         SCL = 0;
  328.                 }
  329.                 TX_buffer = TX_buffer<<1; //左移一位
  330.                 delayNOP();
  331.         }
  332.         delayNOP();
  333.         //check_ACK(); //
  334.         //return (CHACK);                      
  335.                                                                         
  336. }
  337. /*------------------------------------------------------
  338. 接收一个字节
  339. 函数名: RX_byte
  340. 功能: 在SMBus总线上接收一个字节
  341. 参数: unsigned char ack_nack (确认位)
  342. 0 - 主控器件发送 ACK
  343. 1 - 主控器件发送 NACK
  344. 返回值:  unsigned char RX_buffer (总线接收的字节)
  345. 注解: 先接收字节的高位
  346. //-------------------------------------------------------*/
  347. unsigned char RX_byte(unsigned char ack_nack)
  348. {
  349.     unsigned char RX_buffer;
  350.     unsigned char Bit_counter;
  351.     for(Bit_counter=8;Bit_counter;Bit_counter--)
  352.     {
  353.                 if(receive_bit()==1)                        //由SDA线读取一位
  354.                    {
  355.                         RX_buffer<<=1;                   //如果位为"1",赋"1"给RX_buffer
  356.                         RX_buffer|=0x01;
  357.                    }
  358.                 else                                   //如果位为"0",赋"0"给RX_buffer
  359.                    {
  360.                         RX_buffer<<=1;
  361.                         RX_buffer&=0xfe;
  362.                    }               
  363.       }
  364.          send_bit(ack_nack);                           //发送确认位
  365.          return RX_buffer;
  366. }
  367. //-------------------------------------------------------------//


  368. /*---------------------------------------------------
  369. 由MLX90614 RAM/EEPROM 读取的数据
  370. 函数名: MEM_READ
  371. 功能: 给定受控地址和命令时由MLX90614读取数据
  372. 参数: unsigned char slave_addR (受控地址)
  373.          unsigned char cmdR (命令)
  374. 返回值: unsigned long int Data
  375. //-------------------------------------------------*/
  376. unsigned long int MEM_READ(unsigned char slave_addR, unsigned char cmdR)
  377. {        
  378.          unsigned char DataL;                         //
  379.          unsigned char DataH;                                 //由MLX90614读取的数据包
  380.          unsigned char PEC;                                    //
  381.          unsigned long int Data;                        //由MLX90614返回的寄存器数值
  382.          unsigned char Pecreg;                                //存储计算所得PEC字节
  383.          unsigned char arr[6];                                 //存储已发送字节的缓冲器
  384.          unsigned char ack_nack;
  385.          unsigned char SLA;                                                                                
  386.          SLA=(slave_addR<<1);
  387.             begin:                             
  388.          start_bit();                                                        //发送起始位
  389.          TX_byte(SLA);   
  390.                  delayNOP();  //发送受控器件地址,写命令
  391.          if(slave_ack()==0)
  392.          {
  393.          comsend(0xaa);
  394.              stop_bit();
  395.              goto begin;
  396.      }                                                  //发送命令
  397.      comsend(0xBB);
  398.      TX_byte(cmdR);
  399.          if(slave_ack()==0)
  400.          {
  401.              stop_bit();
  402.              goto begin;
  403.      }                                       
  404.          start_bit();                   //发送重复起始位                                
  405.          TX_byte(SLA+1);          //发送受控器件地址,读命令
  406.          if(slave_ack()==0)
  407.          {
  408.              stop_bit();
  409.              goto begin;
  410.          }
  411.          DataL=RX_byte(0);                                                                                 
  412.          DataH=RX_byte(0);                        //读取两个字节数据         
  413.          PEC=RX_byte(ack_nack);            //读取MLX90614的PEC码
  414.          if(ack_nack==1)                    //主控器件发送ack 或是 nack 取决于pec计算,如果PEC是不正确的,发送nack并返回到goto begin
  415.          {
  416.              stop_bit();
  417.              goto begin;
  418.          }                                                
  419.          stop_bit();               //发送终止位
  420.          arr[5]=(SLA);
  421.      arr[4]=cmdR;
  422.      arr[3]=(SLA+1);               
  423.      arr[2]=DataL;
  424.      arr[1]=DataH;
  425.      arr[0]=0;                                                                                                   
  426.         // Pecreg=PEC_cal(arr,6);                            //调用计算 CRC 的函数
  427.          if(PEC==Pecreg)
  428.          {
  429.                 ack_nack=0;
  430.          }
  431.          else
  432.          {
  433.                 ack_nack=0;
  434.          }
  435.          Data=(DataH*256)+DataL;
  436.          return Data;
  437. }


  438. void main()
  439. {
  440.         uint Tem,yy; //温度变量
  441.         uchar tm1,tm2;
  442.                 unsigned char slaveaddress;                                                                   
  443.                 unsigned long int DATA;
  444.                         unsigned int *mahm;
  445.          lcd_init();
  446.          init_serial() ;
  447.          SCL=1;        
  448.          delay_nus(1200);         
  449.         SCL=0;                                                                                  //
  450.         delay_nus(1200);                                                                 //SMBus request,Switch PWM mode to SMBus mode(at least 2ms)
  451.          SCL=1;                                                                            //
  452.                  while(1)
  453.                  {
  454.                           slaveaddress=MEM_READ(0x00,0x2E);                                           //Get the slave address which stored in EEPROM "0Eh"
  455.                           DATA=MEM_READ(slaveaddress,0x07);                                                    //Read Object Temperature from MLX90614 RAM 07h
  456.                        
  457.                 tm1   =DATA%256;
  458.                 tm2=   DATA/256;
  459.                 comsend(tm2);
  460.                 comsend(tm1);  
  461.                         sprintf(dis2,"%d",DATA);
  462.         display(0x00,dis2);       
  463.         delayms(10);                  
  464.                                        
  465.                    }

  466.         /*while(1)
  467.         {
  468.         Tem=readtemp(); //读取温度
  469.               tm1   =Tem%256;
  470.                 tm2=   Tem/256;
  471.                 comsend(tm2);
  472.                 comsend(tm1);
  473.         sprintf(dis2,"%d",Tem);
  474.         display(0x00,dis2);       
  475.         delayms(10);                        
  476.         } */

  477. }
复制代码
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。