找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1958|回复: 0
打印 上一主题 下一主题
收起左侧

51单片机实现红外探头ADC数值读取程序 实现红外巡线

[复制链接]
跳转到指定楼层
楼主
使用单片机型号STC15W408AS-35I-DIP20,焊接效果如附件图。使用程序可以读取所有红外探头的ADC数值,可以进行IIC通信。
这种单片机一次具有8个ADC,一个芯片就能实现8个探头的数据转换。

这样的设计可以实现红外巡线等功能。



# 红外巡线测试结果

2022年8月23日23:10:10

## 装车效果

只装了一块弯的,效果很好。

探头顶端距离地面大约8mm(目测)。

## 我的程序

### 从机

从机传输数据的时候LED亮起。

6个探头的从机传回的数据:\[data*6] \[0] \[addr]

8个探头的从机传回的数据:\[data*8]

### 主机

主机使用STM32F401CCU6,配置IIC2引脚,波特率为一个非标准的传输波特率(10000,标准值为100k(标准IIC)或400k(高速IIC))。

主机对所有地址的从机进行检测,对每个从机,会循环尝试传输,直到传输成功或传输次数达到5次为止。

把所有从机地址检测完毕之后重新开始。

主机接收到数据之后通过UART(115200)传输给电脑,使用串口调试助手(HEX)可以打开查看。

## 数据传输

使用IIC总线传输,经过我的调试,可以在8从机上稳定运行。

总共只需要4个线,2电源线和2数据线。

## 测试数据结果

悬空 0x00-0x10

黑 0x08-0x20

白 0xB0-0xFF

## 测试样例

![示意图](示意图.jpg)

顺时针方向分别是0和1号,也就是上图中左边是1、右边是0;测得数据:

```MATLAB
EC F2 C8 16 14 13 01 00 31 AC D8 F2 EF C0 01 01
EC F2 C8 16 15 13 01 00 31 AC D8 F2 EF C0 01 01
EC F2 C8 16 14 13 01 00 31 AC D8 F2 EF C0 01 01
EC F2 C8 16 14 13 01 00 31 AC D8 F2 EF C0 01 01
EC F2 C8 16 15 13 01 00 31 AC D8 F2 EF C0 01 01
EC F2 C8 16 14 13 01 00 31 AC D8 F2 EF C0 01 01
EC F2 C8 16 14 13 01 00 31 AC D8 F2 EF C0 01 01
EC F2 C8 16 14 13 01 00 31 AC D8 F2 EF C0 01 01
EC F2 C8 16 15 13 01 00 31 AC D8 F2 EF C0 01 01
EC F2 C8 16 14 13 01 00 31 AC D8 F2 EF C0 01 01
EC F2 C8 16 14 13 01 00 31 AC D8 F2 EF C0 01 01
EC F2 C8 16 14 13 01 00 31 AC D8 F2 EF C0 01 01
EC F2 C8 16 15 13 01 00 31 AC D8 F2 EF C0 01 01
EC F2 C8 16 14 13 01 00 31 AC D8 F2 EF C0 01 01
EC F2 C8 16 14 13 01 00 31 AC D8 F2 EF C0 01 01
EC F2 C8 16 14 13 01 00 31 AC D8 F2 EF C0 01 01
EC F2 C8 16 15 13 01 00 31 AC D8 F2 EF C0 01 01
```

数据格式:

\[数据*6](每个探头的ADC转换值,从左到右) \[发送成功所使用的的次数] \[从机地址]

- 位于白色上面的data\[0]\[0:3]给出了白色范围内的值
- 位于黑色上面的data\[0]\[4:6]给出了黑色范围内的值
- 位于过渡位置的data\[1]\[0]给出了中间值0x31,偏离过渡位置的data\[1]\[1]给出了比较靠近白色的值
- 位于白色上面的data\[1]\[2:6]给出了白色范围内的值
- 所有传输均使用1次尝试完成
- 可以连续运行10分钟无故障

## 其他

经过测试,也可以比较好地分辨出紫色、蓝色等。

## 总结

本次实验比较成功,我设计的系统比较安全、灵敏、可靠、高效。

单片机源程序如下:
  1. #include <I2C.h>
  2. #include <STC15.h>
  3. #include <intrins.h>

  4. // #include "./include/delay.h"

  5. sbit LED         = P3 ^ 4;
  6. sbit I2C_SCL = P3 ^ 6;
  7. sbit I2C_SDA = P3 ^ 7;

  8. #if 0
  9. //定义LED灯引脚
  10. sbit Data[8] = {P37, P36, P35, P33, P32, P31, P30, P54};
  11. #endif

  12. void delay(unsigned int delay_time) // 1毫秒@22.1184MHz
  13. {
  14.         unsigned char i, j;
  15.         for (; delay_time > 0; delay_time--) {
  16.                 _nop_();
  17.                 _nop_();
  18.                 i = 22;
  19.                 j = 128;
  20.                 do {
  21.                         while (--j)
  22.                                 ;
  23.                 } while (--i);
  24.         }
  25. }

  26. void                  InitADC();
  27. unsigned char GetADCResult(unsigned char ch);

  28. #define ADC_POWER 0x80         // ADC电源控制位
  29. #define ADC_FLAG 0x10         // ADC完成标志
  30. #define ADC_START 0x08         // ADC起始控制位
  31. #define ADC_SPEEDLL 0x00 // 540个时钟
  32. #define ADC_SPEEDL 0x20         // 360个时钟
  33. #define ADC_SPEEDH 0x40         // 180个时钟
  34. #define ADC_SPEEDHH 0x60 // 90个时钟

  35. /*----------------------------
  36. 初始化ADC
  37. ----------------------------*/
  38. void InitADC() {
  39.         P1ASF          = 0xff; //设置P1口为AD口,0xff表示8通道全开
  40.         ADC_RES          = 0;          //清除结果寄存器
  41.         ADC_CONTR = ADC_POWER | ADC_SPEEDLL;
  42.         delay(20); // ADC上电并延时
  43. }

  44. /*----------------------------
  45. 读取ADC结果
  46. ----------------------------*/
  47. unsigned char GetADCResult(unsigned char ch) {
  48.         ADC_CONTR = ADC_POWER | ADC_SPEEDLL | ch | ADC_START;
  49.         _nop_(); //等待4个NOP
  50.         _nop_();
  51.         _nop_();
  52.         _nop_();
  53.         while (!(ADC_CONTR & ADC_FLAG))
  54.                 ;                                        //等待ADC转换完成
  55.         ADC_CONTR &= ~ADC_FLAG; // Close ADC

  56.         return ADC_RES; //返回ADC结果
  57. }
  58. /*
  59. void test(void){
  60.                 while(1){
  61.                                 I2C_SCL=1;
  62.                                 delay(10);
  63.                                 I2C_SDA=1;
  64.                                 delay(10);
  65.                                 I2C_SCL=0;
  66.                                 delay(10);
  67.                                 I2C_SDA=0;
  68.                                 delay(10);
  69.                                 LED = !LED;
  70.                 }
  71. }*/

  72. /*----------------------------
  73. 主程序由此开始
  74. ----------------------------*/

  75. #define ADDR 0x17 //定义从机地址/编号

  76. unsigned char TX_data[2], ADC_data[8], i;

  77. void main() {
  78.         LED = 1;
  79.         InitADC();
  80.         delay(10);
  81.         while (1) {
  82.                 for (i = 0; i < 8; i++)
  83.                         ADC_data[7 - i] = GetADCResult(i);

  84.                 // TX_data[0] = 0; //初始化为没有黑线
  85.                 // TX_data[1] = 0; //初始化为从第0个位置找到黑线
  86.                 // for (i = 0; i < 8; i++) {
  87.                 //         if (ADC_data[i] < 0x40) { //扫描到黑线
  88.                 //                 TX_data[1] = i;                                          //从第i个开始扫到黑线
  89.                 //                 i++;
  90.                 //                 TX_data[0]++; //扫描到黑线的数量
  91.                 //                 while (i < 8 && ADC_data[i] < 0x40) {
  92.                 //                         i++;
  93.                 //                         TX_data[0]++;
  94.                 //                 }
  95.                 //                 break;
  96.                 //         }
  97.                 // }

  98.                 // while (!I2C_Write(TX_data, ADDR, 2))
  99.                 //         ;
  100.                 P37 = ADC_data[0] > 0x38 ? 1 : 0;
  101.                 P36 = ADC_data[1] > 0x40 ? 1 : 0;
  102.                 P35 = ADC_data[2] > 0x40 ? 1 : 0;
  103.                 P33 = ADC_data[3] > 0x40 ? 1 : 0;
  104.                 P32 = ADC_data[4] > 0x40 ? 1 : 0;
  105.                 P31 = ADC_data[5] > 0x40 ? 1 : 0;
  106.                 P30 = ADC_data[6] > 0x40 ? 1 : 0;
  107.                 P54 = ADC_data[7] > 0x38 ? 1 : 0;
  108.                 delay(1);
  109.         }
  110. }
复制代码

  1. #include "STC15.h"
  2. #include "./include/delay.h"
  3. #include <intrins.h>

  4. sbit LED = P3 ^ 4;

  5. #define I2CDelay() \
  6.         {              \
  7.                 _nop_();   \
  8.                 _nop_();   \
  9.                 _nop_();   \
  10.                 _nop_();   \
  11.         }
  12. sbit I2C_SCL = P3 ^ 6;
  13. sbit I2C_SDA = P3 ^ 7;

  14. /* I2C总线写操作,dat-待写入字节,返回值-主机应答位的值 */
  15. bit I2CWrite(unsigned char dat)
  16. {
  17.         bit ack;                        //用于暂存应答位的值
  18.         unsigned char mask; //用于探测字节内某一位值的掩码变量

  19.         for (mask = 0x80; mask != 0; mask >>= 1) //从高位到低位依次进行
  20.         {
  21.                 if ((mask & dat) == 0) //该位的值输出到SDA上
  22.                         I2C_SDA = 0;
  23.                 else
  24.                         I2C_SDA = 1;
  25.                 while (I2C_SCL == 0)
  26.                         ; //等待SCL上升沿
  27.                 while (I2C_SCL == 1)
  28.                         ; //等待SCL下降沿
  29.         }
  30.         I2C_SDA = 1; // 8位数据发送完后,从机释放SDA,以检测应答
  31.         while (I2C_SCL == 0)
  32.                 ;                   //等待SCL上升沿
  33.         ack = I2C_SDA; //读取此时的SDA值,即为从机的应答值
  34.         while (I2C_SCL == 1)
  35.                 ; //等待SCL下降沿

  36.         return (~ack); //应答值取反以符合通常的逻辑:
  37.                                    // 0=不存在或忙或写入失败,1=存在且空闲或写入成功
  38. }
  39. /* I2C总线读操作,并发送非应答信号,返回值-读到的字节 */
  40. unsigned char I2CReadNAK(unsigned char addr)
  41. {
  42.         unsigned char mask;
  43.         unsigned char dat = 0;

  44.         // I2C_SDA = 1;  //首先确保释放SDA
  45.         // I2C_SCL = 1;  //首先确保释放SDA
  46.         for (mask = 0x80; mask != 0; mask >>= 1) //从高位到低位依次进行
  47.         {
  48.                 while (I2C_SCL == 0)
  49.                         ;                          //等待SCL上升沿
  50.                 if (I2C_SDA == 0) //读取SDA的值
  51.                         dat &= ~mask; //为0时,dat中对应位清零
  52.                 else
  53.                         dat |= mask; //为1时,dat中对应位置1
  54.                 while (I2C_SCL == 1)
  55.                         ; //等待SCL下降沿
  56.         }
  57.         if ((dat >> 1) == addr)
  58.                 I2C_SDA = 0; //地址正确,发送应答信号
  59.         else
  60.                 I2C_SDA = 1; //地址错误,发送非应答信号
  61.         while (I2C_SCL == 0)
  62.                 ; //等待SCL上升沿
  63.         while (I2C_SCL == 1)
  64.                 ; //等待SCL下降沿
  65.         I2C_SDA = 1;

  66.         return dat;
  67. }

  68. /* 读取函数,buf-数据接收指针,addr-起始地址,len-读取长度 */
  69. /*void I2C_Read(unsigned char *buf, unsigned char addr, unsigned char len)
  70. {
  71.         I2CStart();                //发送重复启动信号
  72.         I2CWrite((addr<<1)|0x01);  //寻址器件,后续为读操作
  73.         while (len > 1)            //连续读取len-1个字节
  74.         {
  75.                 *buf++ = I2CReadACK(); //最后字节之前为读取操作+应答
  76.                 len--;
  77.         }
  78.         *buf = I2CReadNAK();       //最后一个字节为读取操作+非应答
  79.         I2CStop();
  80. }*/
  81. /* 写入函数,buf-源数据指针,addr-起始地址,len-写入长度 */
  82. bit I2C_Write(unsigned char *buf, unsigned char addr, unsigned char len) {
  83.         unsigned char I2C_SDA_new, I2C_SDA_old, get_addr; //,loop;
  84.         // I2C_SDA = 1;  //首先确保释放SDA
  85.         // I2C_SCL = 1;  //首先确保释放SCL
  86.         I2C_SDA_new = I2C_SDA;
  87.         do {
  88.                 do
  89.                         I2C_SDA_old = I2C_SDA_new;
  90.                 while (((I2C_SDA_new = I2C_SDA) == 1) ||
  91.                            (I2C_SDA_old == 0)); //等待SDA下降沿
  92.         } while (I2C_SCL == 0);                        //并且SCL为高电平
  93.         while (I2C_SCL == 1)
  94.                 ; //等待SCL下降沿

  95.         get_addr = (I2CReadNAK(addr) >> 1);

  96.         if (get_addr == addr) {
  97.                 LED = 1;

  98.                 while (len > 0) {
  99.                         I2CWrite(*buf++);
  100.                         // if(I2CWrite(*buf++)==0)break;     //写入一个字节数据
  101.                         len--; //待写入长度计数递减
  102.                 }

  103.                 LED = 0;

  104.                 return 1; //发送成功
  105.         }
  106.         return 0; //发送失败
  107. }
复制代码

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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