目錄
一 前言
二 引言
三 PCF8591介紹
(1)I2C通信
?(2)原理圖中的8591
四 代碼層面
(1)根據題目所給的示范代碼,實現ADC
1 為什么需要返回值,同時返回值是unsigned char?
2 為什么發送地址是0x90?
?(2)根據題目所給的示范代碼,實現DAC
main.c
為什么需要轉化成unsigned int?
一 前言
? 本次關于PCF8591的學習,我們主要學ADC和DAC板塊,主要的目標是通過旋轉藍橋杯板子上的旋鈕(電壓采集)和邊上的光敏電阻,來實現PCK8591_ADC板塊的轉換,本次也會教DAC的轉換,但并不寫相關代碼調試
二 引言
我們知道,在電路中傳輸的信號只有兩種,分別是數字信號和模擬信號,模擬信號更像一個個具體的數值,數字信號只由0和1構成。將模擬信號轉換為數字信號,我們把這個過程稱之為ADC轉化,A表示模擬信號,D表示數字信號,所衍生出來了兩種技術:模擬-數字轉換ADC技術、數字-模擬轉換DAC技術,一般來說,我們用模擬-數字轉換ADC技術用的比較多,我也會著重去講ADC技術。(大家不要把ADC想成王者榮耀里面的射手位置啊!!)
三 PCF8591介紹
(1)I2C通信
在藍橋杯比賽中提供的板子原理圖中,上面這張照片就是PCF8591的原理圖,大家仔細觀察本章圖片的右下角位置,你會發現:P20、P21后面的SCL和SDA,這兩個線就是I2C的核心線,I2C需知道的相關底層知識點,如若不理解I2C通信,推薦大家去嗶哩嗶哩看這個博主的視頻
【4分鐘看懂!I2C通訊協議 最簡單的總線通訊!】 https://www.bilibili.com/video/BV1dg4y1H773/?share_source=copy_web
1 SDA:提供信息通道? ? ? ?SCL:提供精確的頻率????????GND:接地線
2 當SCL為高電平時:(1)SDA從高到低的跳變為開始信號(2)SDA從低到高的跳變為結束信號
3 主機每次發送信息只能發送八個二進制數(1字節byte)
4 先寫在讀
大家先對上面這張圖片有所印象,我會在后面結合比賽給提供的代碼中進行添加代碼講解,因為比賽所提供的范例代碼已經包含上面這個過程了
?(2)原理圖中的8591
現在我們觀察左上角的這個幾個位置,這幾個位置是決定著PCF8591該作用到那個地方,例如下圖(從原理圖中摘出來的部分)+對應功能的地址(代碼要寫對應的地址):
地址 | 對應的功能 | |
---|---|---|
AIN1 | 0x41 | 光敏電阻 |
AIN3 | 0x43 | 滑動變阻器 |
四 代碼層面
(1)根據題目所給的示范代碼,實現ADC
我們先看一下范例代碼給我們提供了什么:
static void I2C_Delay(unsigned char n);//延時函數
void I2CStart(void); //開始信號
void I2CStop(void); //停止信號
void I2CSendByte(unsigned char byt);//發送一個字節
unsigned char I2CReceiveByte(void); //接收一個字節
unsigned char I2CWaitAck(void);//等待響應
void I2CSendAck(unsigned char ackbit);//發送應答位
我們根據上面比賽提供的代碼進行ADC轉換,由于我們知道在板子上ADC有兩個,分別是光敏電阻和滑動變阻器,所以我們需要在代碼書寫的時候要進行選擇,引入入口參數channel_num,再在對應的.h文件中,將兩個參數進行宏定義,我們如果想要用哪個功能只需要給對應的函數進行更換入口參數即可。
#define Photo_Res_Channel 0x41 //光敏電阻
#define Adj_Res_Channel 0x43 //滑動變阻器
在官方給的IIC.c文件中的最下面添加相應的代碼:
unsigned char Pcf8591_Adc(unsigned char channel_num_contrl)
{unsigned char temp;I2CStart();//發送開啟信號I2CSendByte(0x90);//選擇PCF8591芯片,確定寫的模式I2CWaitAck();//等待PCF8591反饋I2CSendByte(channel_num_contrl);//確定要轉換的通道(順便,使能DA轉換)I2CWaitAck();//等待PCF8591反饋 I2CStart();//發送開啟信號I2CSendByte(0x91);//選擇PCF8591芯片,確定讀的模式I2CWaitAck();//等待PCF8591反饋 temp = I2CReceiveByte();//接收數據I2CSendAck(1);//選擇不應答I2CStop();//停止發送return temp;}
1 為什么需要返回值,同時返回值是unsigned char?
函數內部通過 IIC 總線從 PCF8591 讀取的數據(存儲在 temp中),temp是轉換結果,必須通過返回值返回給用戶,否則無法獲取 ADC 結果
PCF8591 是一個 8 位 ADC(模數轉換器)
2 為什么發送地址是0x90?
0x90 = 1001 0000,高四位分別是1001,1001的意思就是PCF8591,然后最后一位決定著讀還是寫,0是寫,1是讀,再看上面PCF8591的原理圖的A1 2 3部分,他們仨是接地的,所以0x90的意思就是我PCF8591要寫數據了,若不理解,就背下來!!!
?整體的一個代碼過程就是:
開始信號 -> 寫 -> 等待應答
告訴單片機對應的通道?->?等待應答
開始信號 -> 讀 - > 等待應答
將接受到的數據給temp -> 8591告訴單片機不應答 -> 停止信號
?(2)根據題目所給的示范代碼,實現DAC
?同樣,在iic.c文件中,繼續添加相應的DAC轉換代碼:
void Pcf8591_Dac(unsigned char trans_dat)
{I2CStart();//發送開啟信號I2CSendByte(0x90);//選擇PCF8591芯片,確定寫的模式I2CWaitAck();//等待PCF8591反饋I2CSendByte(0x41);//使能DA轉換(隨便寫通道編號,不影響,主要的功能是使能DA)I2CWaitAck();//等待PCF8591反饋?? ??? ?I2CSendByte(trans_dat);//將待轉換的數據發送出去I2CWaitAck();//等待PCF8591反饋?? ?I2CStop();//停止發送?? ?}
注意:
這里和上面ADC很多地方不一樣,這里不用接收信號函數??I2CReceiveByte(),以及不用引用其他變量
main.c
在main.c中,僅需添加一種新的情況,全部代碼我就不寫了,和本專題前面的main文件中的代碼類似,請大家認真閱讀曾經的文章
case 4:sprintf(seg_string,"%4d%4d",(unsigned int)PCF8591_ADC(Photo_Res_Channel ),(unsigned int)PCF8591_ADC(Adjust_Channel));//為什么最后顯示的是左邊是光敏電阻,右邊是光敏電阻break;
這里面我們也需要將ADC讀取的光敏電阻傳到數碼管上,需要利用上面這行代碼
為什么需要轉化成unsigned int?
因為PCF8591_ADC,這個函數的返回值是unsigned char,數碼管顯示不了字符型(char),所以我們需要將返回值強行轉化成unsigned int類型