1. ADC介紹
ADC是什么?
- Analog-to-Digital Converter,指模擬/數字轉換器
ADC的性能指標
- 量程:能測量的電壓范圍
- 分辨率:ADC能辨別的最小模擬量,通常以輸出二進制數的位數表示,比如:8、10、12、16 位等;位數越多,分辨率越高,一般來說分辨率越高,轉化時間越長
- 轉換時間:從轉換開始到獲得穩定的數字量輸出所需要的時間稱為轉換時間
ADC特性
- 12 位精度下轉換速度可高達 1MHZ
- 供電電壓:V SSA :0V,V DDA :2.4V~3.6V
- ADC 輸入范圍:VREF- ≤ VIN ≤ VREF+(0–3.6V)
- 采樣時間可配置,采樣時間越長,轉換結果相對越準確,但是轉換速度就越慢
- ADC 的結果可以左對齊或右對齊方式存儲在 16 位數據寄存器中
ADC通道
- 總共 2 個 ADC(ADC1,ADC2),每個 ADC 有 18 個轉換通道: 16 個外部通道、 2 個內部通道(溫度傳感器、內
部參考電壓)。
- 外部的 16 個通道在轉換時又分為規則通道和注入通道,其中規則通道最多有 16 路,注入通道最多有 4 路。
- 規則組:正常排隊的人;
- 注入組:有特權的人(軍人、孕婦)
ADC轉換順序
- 每個 ADC 只有一個數據寄存器,16 個通道一起共用這個寄存器,所以需要指定規則轉換通道的轉換順序。
- 規則通道中的轉換順序由三個寄存器控制:SQR1、SQR2、SQR3,它們都是 32 位寄存器。
- SQR 寄存器控制著轉換通道的數目和轉換順序,只要在對應的寄存器位 SQx 中寫入相應的通道,這個通道就是第 x 個轉換。
- 和規則通道轉換順序的控制一樣,注入通道的轉換也是通過注入寄存器來控制,只不過只有一個 JSQR 寄存器
來控制,控制關系如下:
- 注入序列的轉換順序是從JSQx[ 4 : 0 ](x=4-JL[1:0])開始。只有當JL=4的時候,注入通道的轉換順序才會按
照JSQ1、JSQ2、JSQ3、JSQ4的順序執行。
ADC觸發方式
- 通過向控制寄存器ADC-CR2的ADON位寫1來開啟轉換,寫0停止轉換。
- 也可以通過外部事件(如定時器)進行轉換。
ADC轉化時間
- ADC 是掛載在 APB2 總線(PCLK2)上的,經過分頻器得到 ADC 時鐘(ADCCLK),最高 14 MHz。
- 轉換時間=采樣時間+12.5個周期
- 12.5 個周期是固定的,一般我們設置 PCLK2=72M,經過 ADC 預分頻器能分頻到最大的時鐘只能是 12M,
采樣周期設置為 1.5 個周期,算出最短的轉換時間為 1.17us。
ADC轉化模式
掃描模式
- 關閉掃描模式:只轉換 ADC_SQRx 或 ADC_JSQR 選中的第一個通道
- 打開掃描模式:掃描所有被 ADC_SQRx 或 ADC_JSQR 選中的所有通道
單次轉換/連續轉換
- 單次轉換:只轉換一次
- 連續轉換:轉換一次之后,立馬進行下一次轉換
2. 使用ADC讀取煙霧傳感器的值(351.55)
- STM32CubeMx工程配置
- 代碼(21.adc_test/MDK-ARM)
uint32_t smoke_value = 0;
while (1)
{HAL_ADC_Start(&hadc1); //啟動ADC單次轉換HAL_ADC_PollForConversion(&hadc1, 50); //等待ADC轉換完成smoke_value = HAL_ADC_GetValue(&hadc1); //讀取ADC轉換數據printf("smoke_value = %f\r\n", 3.3/4096 * smoke_value);//電壓值//printf("smoke_value = %d \r\n", smoke_value);//多少個刻度HAL_Delay(500);
}
3. llC介紹及OLED寫數據函數封裝(352.56)
- 筆記參照:上官一號筆記第5章節;
- 視頻參照:上官一號92~103節
函數封裝
- 用到的庫函數:
HAL_StatusTypeDef HAL_I2C_Mem_Write(I2C_HandleTypeDef *hi2c,uint16_t DevAddress,uint16_t MemAddress,uint16_t MemAddSize,uint8_t *pData,uint16_t Size,uint32_t Timeout)
參數一:I2C_HandleTypeDef *hi2c,I2C設備句柄
參數二:uint16_t DevAddress,目標器件的地址,七位地址必須左對齊
參數三:uint16_t MemAddress,目標器件的目標寄存器地址
參數四:uint16_t MemAddSize,目標器件內部寄存器地址數據長度
參數五:uint8_t *pData,待寫的數據首地址
參數六:uint16_t Size,待寫的數據長度
參數七:uint32_t Timeout,超時時間
返回值:HAL_StatusTypeDef,HAL狀態(OK,busy,ERROR,TIMEOUT)
- 向OLED寫命令的封裝:
void Oled_Write_Cmd(uint8_t dataCmd)
{HAL_I2C_Mem_Write(&hi2c1, 0x78, 0x00, I2C_MEMADD_SIZE_8BIT,&dataCmd, 1, 0xff);
}
- 向OLED寫數據的封裝:
void Oled_Write_Data(uint8_t dataData)
{HAL_I2C_Mem_Write(&hi2c1, 0x78, 0x40, I2C_MEMADD_SIZE_8BIT,&dataData, 1, 0xff);
}
- STM32CubeMx工程配置
4. 重做上官一號的IIC實驗(353.57)
- 接線:
- SCL – PB6
- SDA – PB7
- 代碼(22.oled_test/MDK-ARM)(重新封裝了Oled_Write_Cmd、Oled_Write_Data,其他和51代碼一樣)
5. SPI及W25Q128介紹(354.58)
SPI 是什么?
- SP I是串行外設接口(Serial Peripheral Interface)的縮寫,是一種高速的,全雙工,同步的通信總線,并且
在芯片的管腳上只占用四根線,節約了芯片的管腳,同時為 PCB 的布局上節省空間,提供方便,正是出于這
種簡單易用的特性,越來越多的芯片集成了這種通信協議,比如 AT91RM9200 。
SPI 物理架構
- SPI 包含 4 條總線,SPI 總線包含 4 條總線,分別為 SS、SCK、MOSI、MISO。它們的作用介紹如下 :
(1) MISO – Master Input Slave Output,主設備數據輸入,從設備數據輸出
(2) MOSI – Master Output Slave Input,主設備數據輸出,從設備數據輸入
(3) SCK – Serial Clock,時鐘信號,由主設備產生
(4) CS – Chip Select,片選信號,由主設備控制
SPI 工作原理
SPI 工作模式
- 時鐘極性(CPOL):
- 沒有數據傳輸時時鐘線的空閑狀態電平
- 0:SCK在空閑狀態保持低電平
- 1:SCK在空閑狀態保持高電平
- 時鐘相位(CPHA):
- 時鐘線在第幾個時鐘邊沿采樣數據
- 0:SCK的第一(奇數)邊沿進行數據位采樣,數據在第一個時鐘邊沿被鎖存
- 1:SCK的第二(偶數)邊沿進行數據位采樣,數據在第二個時鐘邊沿被鎖存
- 模式 0 和模式 3 最常用。
- 模式 0 時序圖:
- 模式 3 時序圖:
什么是 W25Q128 ?
- W25Q128 是華邦公司推出的一款 SPI 接口的 NOR Flash 芯片,其存儲空間為 128 Mbit,相當于 16M 字
節。 - Flash 是常用的用于儲存數據的半導體器件,它具有容量大,可重復擦寫、按“扇區/塊”擦除、掉電后數據可
繼續保存的特性。 - Flash 是有一個物理特性:只能寫 0 ,不能寫 1 ,寫 1 靠擦除。
W25Q128 存儲架構
- 一般按扇區(4k)進行擦除。
- 可以按 章 – 節 – 頁 – 字 進行理解。
W25Q128 常用指令
- W25Q128 全部指令非常多,但常用的如下幾個指令:
- 寫使能 (06H)
- 執行頁寫,扇區擦除,塊擦除,片擦除,寫狀態寄存器等指令前,需要寫使能。
- 拉低 CS 片選 → 發送 06H → 拉高 CS 片選
- 讀狀態寄存器(05H)
- 拉低CS片選 → 發送05H→ 返回SR1的值 → 拉高CS片選
- 讀時序(03H)
- 拉低CS片選 → 發送03H→ 發送24位地址 → 讀取數據(1~n) → 拉高CS片選
- 頁寫時序 (02H)
- 頁寫命令最多可以向FLASH傳輸256個字節的數據。
- 拉低CS片選 → 發送02H→ 發送24位地址 → 發送數據(1~n) → 拉高CS片選
- 扇區擦除時序(20H)
- 寫入數據前,檢查內存空間是否全部都是 0XFF ,不滿足需擦除。
- 拉低CS片選 → 發送20H→ 發送24位地址 → 拉高CS片選
W25Q128 狀態寄存器
- W25Q128 一共有 3 個狀態寄存器,它們的作用是跟蹤芯片的狀態。
- 其中,狀態寄存器 1 較為常用。
- BUSY:指示當前的狀態,0 表示空閑,1 表示忙碌
- WEL:寫使能鎖定,為 1 時,可以操作頁/扇區/塊。為 0 時,寫禁止。
W25Q128 常見操作流程
- 以下流程省略了拉低/拉高片選信號CS。
- 讀操作:
- 擦除扇區:
- 寫操作:
5. 使用SPI通訊讀寫W25Q128模塊(355.59)
硬件接線
- VCC – 3.3V
- CS – PA4
- CLK – PA5
- DO – PA6
- DI – PA7
cubeMX配置
w25q128_write_nocheck流程圖
- 代碼(27.spi_test/MDK-ARM)
6. LCD1602介紹及實戰(356.60)
項目需求
- 使用溫濕度傳感器模塊(DHT11)獲取溫度及濕度,并將值顯示在LCD1602上,同時通過藍牙模塊透傳到手
機。
項目框圖
硬件清單
- DHT11
- LCD1602
- HC-08
- 繼電器
- 杜邦線
LCD1602硬件接線
- D0 ~ D7 – A0 ~ A7
- RS – B1
- RW – B2
- EN – B10
- V0 – GND(正視看不到顯示結果,需要側著看。否則需要接可調電阻)
- VSS – GND
- VDD – 5V(工作電源)
- BLA – 5V(背光燈電源)
- BLK – GND
cubemx配置
引腳封裝
- RS、RW、EN三根信號線經常需要進行拉高/拉低操作,可以進行封裝
#define RS_GPIO_Port GPIOB
#define RW_GPIO_Port GPIOB
#define EN_GPIO_Port GPIOB
#define RS_Pin GPIO_PIN_1
#define RW_Pin GPIO_PIN_2
#define EN_Pin GPIO_PIN_10
#define RS_HIGH HAL_GPIO_WritePin(RS_GPIO_Port, RS_Pin, GPIO_PIN_SET)
#define RS_LOW HAL_GPIO_WritePin(RS_GPIO_Port, RS_Pin, GPIO_PIN_RESET)
#define RW_HIGH HAL_GPIO_WritePin(RW_GPIO_Port, RW_Pin, GPIO_PIN_SET)
#define RW_LOW HAL_GPIO_WritePin(RW_GPIO_Port, RW_Pin, GPIO_PIN_RESET)
#define EN_HIGH HAL_GPIO_WritePin(EN_GPIO_Port, EN_Pin, GPIO_PIN_SET)
#define EN_LOW HAL_GPIO_WritePin(EN_GPIO_Port, EN_Pin, GPIO_PIN_RESET)
- 如何將一個字節的數據按位一次性發送到GPIOA的8個管腳?
GPIOA->ODR = cmd;
代碼實現
代碼(24.lcd1602_test/MDK-ARM)
#define RS_GPIO_Port GPIOB
#define RW_GPIO_Port GPIOB
#define EN_GPIO_Port GPIOB
#define RS_Pin GPIO_PIN_1
#define RW_Pin GPIO_PIN_2
#define EN_Pin GPIO_PIN_10
#define RS_HIGH HAL_GPIO_WritePin(RS_GPIO_Port, RS_Pin, GPIO_PIN_SET)
#define RS_LOW HAL_GPIO_WritePin(RS_GPIO_Port, RS_Pin, GPIO_PIN_RESET)
#define RW_HIGH HAL_GPIO_WritePin(RW_GPIO_Port, RW_Pin, GPIO_PIN_SET)
#define RW_LOW HAL_GPIO_WritePin(RW_GPIO_Port, RW_Pin, GPIO_PIN_RESET)
#define EN_HIGH HAL_GPIO_WritePin(EN_GPIO_Port, EN_Pin, GPIO_PIN_SET)
#define EN_LOW HAL_GPIO_WritePin(EN_GPIO_Port, EN_Pin, GPIO_PIN_RESET)
void Write_Cmd_Func(uint8_t cmd)
{RS_LOW;RW_LOW;EN_LOW;GPIOA->ODR = cmd;HAL_Delay(5);EN_HIGH;HAL_Delay(5);EN_LOW;
}
void Write_Data_Func(uint8_t dataShow)
{RS_HIGH;RW_LOW;EN_LOW;GPIOA->ODR = dataShow;HAL_Delay(5);EN_HIGH;HAL_Delay(5);EN_LOW;
}
void LCD1602_INIT(void)
{
//(1)延時 15msHAL_Delay(15);
//(2)寫指令 38H(不檢測忙信號)Write_Cmd_Func(0x38);
//(3)延時 5msHAL_Delay(5);
//(4)以后每次寫指令,讀/寫數據操作均需要檢測忙信號
//(5)寫指令 38H:顯示模式設置Write_Cmd_Func(0x38);
//(6)寫指令 08H:顯示關閉Write_Cmd_Func(0x08);
//(7)寫指令 01H:顯示清屏Write_Cmd_Func(0x01);
//(8)寫指令 06H:顯示光標移動設置Write_Cmd_Func(0x06);
//(9)寫指令 0CH:顯示開及光標設置}Write_Cmd_Func(0x0c);
}
void LCD1602_showLine(char row, char col, char *string)
{switch(row){case 1:Write_Cmd_Func(0x80+col);while(*string){Write_Data_Func(*string);string++;}break;case 2:Write_Cmd_Func(0x80+0x40+col);while(*string){Write_Data_Func(*string);string++;}break;}
}
//main函數里://char position = 0x80 + 0x05;//char dataShow = 'C';LCD1602_INIT();//Write_Cmd_Func(position);//選擇要顯示的地址//Write_Data_Func(dataShow);//發送要顯示的字符LCD1602_showLine(1,6,"NO.2");LCD1602_showLine(2,0,"Jessie handsome");
7. DHT11介紹及實戰(357.61)
硬件接線
- VCC – 5V
- GND – GND
- DAT – PB7
- 注意:PB7既作為輸入,也作為輸出,則不能直接在CubeMX里配置,需要自己寫代碼
cubemx配置
代碼實現
#define DHT_HIGHT HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_SET)
#define DHT_LOW HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_RESET)
#define DHT_VALUE HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_7)
uint8_t datas[5];
void delay_us(uint16_t cnt)
{uint8_t i;while(cnt){for (i = 0; i < 10; i++){}cnt--;}
}
void DHT_GPIO_Init(uint32_t Mode)
{ GPIO_InitTypeDef GPIO_InitStruct = {0};__HAL_RCC_GPIOB_CLK_ENABLE();GPIO_InitStruct.Pin = GPIO_PIN_7;GPIO_InitStruct.Mode = Mode;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
void DHT11_Start(void)
{DHT_GPIO_Init(GPIO_MODE_OUTPUT_PP);DHT_HIGHT;DHT_LOW;HAL_Delay(30);DHT_HIGHT;DHT_GPIO_Init(GPIO_MODE_INPUT);while(DHT_VALUE);while(!DHT_VALUE);while(DHT_VALUE);
}
void Read_Data_From_DHT()
{int i;//輪int j;//每一輪讀多少次char tmp;char flag;DHT11_Start();DHT_GPIO_Init(GPIO_MODE_INPUT);for(i= 0;i < 5;i++){for(j=0;j<8;j++){while(!DHT_VALUE);//等待卡g點delay_us(40);if(DHT_VALUE == 1){flag = 1;while(DHT_VALUE);}else{flag = 0;}tmp = tmp << 1;tmp |= flag;}datas[i] = tmp;}
}
int fputc(int ch, FILE *f)
{ unsigned char temp[1]={ch};HAL_UART_Transmit(&huart1,temp,1,0xffff); return ch;
}
int main(void)
{HAL_Init();SystemClock_Config();MX_GPIO_Init();MX_USART1_UART_Init();
printf("Jessie handsome\r\n");
HAL_Delay(2000);while (1){Read_Data_From_DHT();printf("Humi: %d.%d%% ", datas[0], datas[1]);printf("Temp: %d.%d\r\n ", datas[2], datas[3]);HAL_Delay(2000);}
}
8. 整合DHT11及LCD1602(358.62)
項目設計
- 繼電器數據線插在PB6上,DHT11及LCD1602接線與上述相同。
項目實現
- 注意點:
- 將Use MicroLIB的勾打上;
- 在main函數把串口中斷打開;
- 使用藍牙模塊時,將波特率設置為9600
9. 溫濕度LCD顯示并占傳服務器項目完結(359.63)
char message[16];
while (1)
{Read_Data_From_DHT();if(datas[2] >= 24)HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_RESET);elseHAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_SET);memset(message, 0, sizeof(message));sprintf(message, "Humi: %d.%d%%", datas[0], datas[1]);LCD1602_showLine(1,0, message);sprintf(message, "Temp: %d.%d", datas[2], datas[3]);LCD1602_showLine(2,0, message);HAL_Delay(2000);
}