找回密碼
 立即注冊(cè)

QQ登錄

只需一步,快速開始

搜索
查看: 2035|回復(fù): 0
收起左側(cè)

51單片機(jī)實(shí)現(xiàn)紅外探頭ADC數(shù)值讀取程序 實(shí)現(xiàn)紅外巡線

[復(fù)制鏈接]
ID:1050734 發(fā)表于 2022-11-6 17:25 | 顯示全部樓層 |閱讀模式
使用單片機(jī)型號(hào)STC15W408AS-35I-DIP20,焊接效果如附件圖。使用程序可以讀取所有紅外探頭的ADC數(shù)值,可以進(jìn)行IIC通信。
這種單片機(jī)一次具有8個(gè)ADC,一個(gè)芯片就能實(shí)現(xiàn)8個(gè)探頭的數(shù)據(jù)轉(zhuǎn)換。

這樣的設(shè)計(jì)可以實(shí)現(xiàn)紅外巡線等功能。
IMG_20221106_172232_edit_1858734296485128.jpg IMG_20221106_172239.jpg
示意圖.jpg

# 紅外巡線測(cè)試結(jié)果

2022年8月23日23:10:10

## 裝車效果

只裝了一塊彎的,效果很好。

探頭頂端距離地面大約8mm(目測(cè))。

## 我的程序

### 從機(jī)

從機(jī)傳輸數(shù)據(jù)的時(shí)候LED亮起。

6個(gè)探頭的從機(jī)傳回的數(shù)據(jù):\[data*6] \[0] \[addr]

8個(gè)探頭的從機(jī)傳回的數(shù)據(jù):\[data*8]

### 主機(jī)

主機(jī)使用STM32F401CCU6,配置IIC2引腳,波特率為一個(gè)非標(biāo)準(zhǔn)的傳輸波特率(10000,標(biāo)準(zhǔn)值為100k(標(biāo)準(zhǔn)IIC)或400k(高速IIC))。

主機(jī)對(duì)所有地址的從機(jī)進(jìn)行檢測(cè),對(duì)每個(gè)從機(jī),會(huì)循環(huán)嘗試傳輸,直到傳輸成功或傳輸次數(shù)達(dá)到5次為止。

把所有從機(jī)地址檢測(cè)完畢之后重新開始。

主機(jī)接收到數(shù)據(jù)之后通過UART(115200)傳輸給電腦,使用串口調(diào)試助手(HEX)可以打開查看。

## 數(shù)據(jù)傳輸

使用IIC總線傳輸,經(jīng)過我的調(diào)試,可以在8從機(jī)上穩(wěn)定運(yùn)行。

總共只需要4個(gè)線,2電源線和2數(shù)據(jù)線。

## 測(cè)試數(shù)據(jù)結(jié)果

懸空 0x00-0x10

黑 0x08-0x20

白 0xB0-0xFF

## 測(cè)試樣例

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

順時(shí)針方向分別是0和1號(hào),也就是上圖中左邊是1、右邊是0;測(cè)得數(shù)據(jù):

```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
```

數(shù)據(jù)格式:

\[數(shù)據(jù)*6](每個(gè)探頭的ADC轉(zhuǎn)換值,從左到右) \[發(fā)送成功所使用的的次數(shù)] \[從機(jī)地址]

- 位于白色上面的data\[0]\[0:3]給出了白色范圍內(nèi)的值
- 位于黑色上面的data\[0]\[4:6]給出了黑色范圍內(nèi)的值
- 位于過渡位置的data\[1]\[0]給出了中間值0x31,偏離過渡位置的data\[1]\[1]給出了比較靠近白色的值
- 位于白色上面的data\[1]\[2:6]給出了白色范圍內(nèi)的值
- 所有傳輸均使用1次嘗試完成
- 可以連續(xù)運(yùn)行10分鐘無(wú)故障

## 其他

經(jīng)過測(cè)試,也可以比較好地分辨出紫色、藍(lán)色等。

## 總結(jié)

本次實(shí)驗(yàn)比較成功,我設(shè)計(jì)的系統(tǒng)比較安全、靈敏、可靠、高效。

單片機(jī)源程序如下:
  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完成標(biāo)志
  30. #define ADC_START 0x08         // ADC起始控制位
  31. #define ADC_SPEEDLL 0x00 // 540個(gè)時(shí)鐘
  32. #define ADC_SPEEDL 0x20         // 360個(gè)時(shí)鐘
  33. #define ADC_SPEEDH 0x40         // 180個(gè)時(shí)鐘
  34. #define ADC_SPEEDHH 0x60 // 90個(gè)時(shí)鐘

  35. /*----------------------------
  36. 初始化ADC
  37. ----------------------------*/
  38. void InitADC() {
  39.         P1ASF          = 0xff; //設(shè)置P1口為AD口,0xff表示8通道全開
  40.         ADC_RES          = 0;          //清除結(jié)果寄存器
  41.         ADC_CONTR = ADC_POWER | ADC_SPEEDLL;
  42.         delay(20); // ADC上電并延時(shí)
  43. }

  44. /*----------------------------
  45. 讀取ADC結(jié)果
  46. ----------------------------*/
  47. unsigned char GetADCResult(unsigned char ch) {
  48.         ADC_CONTR = ADC_POWER | ADC_SPEEDLL | ch | ADC_START;
  49.         _nop_(); //等待4個(gè)NOP
  50.         _nop_();
  51.         _nop_();
  52.         _nop_();
  53.         while (!(ADC_CONTR & ADC_FLAG))
  54.                 ;                                        //等待ADC轉(zhuǎn)換完成
  55.         ADC_CONTR &= ~ADC_FLAG; // Close ADC

  56.         return ADC_RES; //返回ADC結(jié)果
  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 //定義從機(jī)地址/編號(hào)

  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個(gè)位置找到黑線
  86.                 // for (i = 0; i < 8; i++) {
  87.                 //         if (ADC_data[i] < 0x40) { //掃描到黑線
  88.                 //                 TX_data[1] = i;                                          //從第i個(gè)開始掃到黑線
  89.                 //                 i++;
  90.                 //                 TX_data[0]++; //掃描到黑線的數(shù)量
  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. }
復(fù)制代碼

  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-待寫入字節(jié),返回值-主機(jī)應(yīng)答位的值 */
  15. bit I2CWrite(unsigned char dat)
  16. {
  17.         bit ack;                        //用于暫存應(yīng)答位的值
  18.         unsigned char mask; //用于探測(cè)字節(jié)內(nèi)某一位值的掩碼變量

  19.         for (mask = 0x80; mask != 0; mask >>= 1) //從高位到低位依次進(jìn)行
  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位數(shù)據(jù)發(fā)送完后,從機(jī)釋放SDA,以檢測(cè)應(yīng)答
  31.         while (I2C_SCL == 0)
  32.                 ;                   //等待SCL上升沿
  33.         ack = I2C_SDA; //讀取此時(shí)的SDA值,即為從機(jī)的應(yīng)答值
  34.         while (I2C_SCL == 1)
  35.                 ; //等待SCL下降沿

  36.         return (~ack); //應(yīng)答值取反以符合通常的邏輯:
  37.                                    // 0=不存在或忙或?qū)懭胧。?=存在且空閑或?qū)懭氤晒?br />
  38. }
  39. /* I2C總線讀操作,并發(fā)送非應(yīng)答信號(hào),返回值-讀到的字節(jié) */
  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) //從高位到低位依次進(jìn)行
  47.         {
  48.                 while (I2C_SCL == 0)
  49.                         ;                          //等待SCL上升沿
  50.                 if (I2C_SDA == 0) //讀取SDA的值
  51.                         dat &= ~mask; //為0時(shí),dat中對(duì)應(yīng)位清零
  52.                 else
  53.                         dat |= mask; //為1時(shí),dat中對(duì)應(yīng)位置1
  54.                 while (I2C_SCL == 1)
  55.                         ; //等待SCL下降沿
  56.         }
  57.         if ((dat >> 1) == addr)
  58.                 I2C_SDA = 0; //地址正確,發(fā)送應(yīng)答信號(hào)
  59.         else
  60.                 I2C_SDA = 1; //地址錯(cuò)誤,發(fā)送非應(yīng)答信號(hào)
  61.         while (I2C_SCL == 0)
  62.                 ; //等待SCL上升沿
  63.         while (I2C_SCL == 1)
  64.                 ; //等待SCL下降沿
  65.         I2C_SDA = 1;

  66.         return dat;
  67. }

  68. /* 讀取函數(shù),buf-數(shù)據(jù)接收指針,addr-起始地址,len-讀取長(zhǎng)度 */
  69. /*void I2C_Read(unsigned char *buf, unsigned char addr, unsigned char len)
  70. {
  71.         I2CStart();                //發(fā)送重復(fù)啟動(dòng)信號(hào)
  72.         I2CWrite((addr<<1)|0x01);  //尋址器件,后續(xù)為讀操作
  73.         while (len > 1)            //連續(xù)讀取len-1個(gè)字節(jié)
  74.         {
  75.                 *buf++ = I2CReadACK(); //最后字節(jié)之前為讀取操作+應(yīng)答
  76.                 len--;
  77.         }
  78.         *buf = I2CReadNAK();       //最后一個(gè)字節(jié)為讀取操作+非應(yīng)答
  79.         I2CStop();
  80. }*/
  81. /* 寫入函數(shù),buf-源數(shù)據(jù)指針,addr-起始地址,len-寫入長(zhǎng)度 */
  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;     //寫入一個(gè)字節(jié)數(shù)據(jù)
  101.                         len--; //待寫入長(zhǎng)度計(jì)數(shù)遞減
  102.                 }

  103.                 LED = 0;

  104.                 return 1; //發(fā)送成功
  105.         }
  106.         return 0; //發(fā)送失敗
  107. }
復(fù)制代碼

評(píng)分

參與人數(shù) 1黑幣 +50 收起 理由
admin + 50 共享資料的黑幣獎(jiǎng)勵(lì)!

查看全部評(píng)分

回復(fù)

使用道具 舉報(bào)

本版積分規(guī)則

小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表