前言:
本系列教程將HAL庫與STM32CubeMX結(jié)合在一起講解,使您可以更快速的學(xué)會各個模塊的使用
在之前的標(biāo)準(zhǔn)庫中,STM32的硬件IIC非常復(fù)雜,更重要的是它并不穩(wěn)定,所以都不推薦使用。
但是在我們的HAL庫中,對硬件IIC做了全新的優(yōu)化,使得之前軟件IIC幾百行代碼,在HAL庫中,只需要寥寥幾行就可以完成 那么這篇文章將帶你去感受下它的優(yōu)異之處
這可能是目前關(guān)于STM32CubeMX的硬件iic 講的最全面和詳細(xì)的一篇文章之一了
所用工具:
1、芯片: STM32F103ZET6
2、STM32CubeMx軟件
3、IDE: MDK-Keil軟件
4、STM32F1xx/STM32F4xxHAL庫
5、IIC: 使用硬件IIC1
知識概括:
通過本篇博客您將學(xué)到:
IIC的基本原理
STM32CubeMX創(chuàng)建IIC例程
HAL庫IIC函數(shù)庫
AT24C02 芯片原理
《IIC原理超詳細(xì)講解—值得一看》。
如果對IIC還不是太了解的朋友請移步到這篇文章中
IIC起始信號和終止信號:
起始信號:SCL保持高電平,SDA由高電平變?yōu)榈碗娖胶螅訒r(>4.7us),SCL變?yōu)榈碗娖健?/p>
停止信號:SCL保持高電平。SDA由低電平變?yōu)楦唠娖健?/p>
【STM32】HAL庫 STM32CubeMX教程四—UART串口通信詳解
5 時鐘源設(shè)置
我的是 外部晶振為8MHz
32的時鐘樹框圖 如果不懂的話請看《【STM32】系統(tǒng)時鐘RCC詳解(超詳細(xì),超全面)》
6 項(xiàng)目文件設(shè)置
1 設(shè)置項(xiàng)目名稱
2 設(shè)置存儲路徑
3 選擇所用IDE
7創(chuàng)建工程文件
然后點(diǎn)擊GENERATE CODE 創(chuàng)建工程
配置下載工具
新建的工程所有配置都是默認(rèn)的 我們需要自行選擇下載模式,勾選上下載后復(fù)位運(yùn)行
IIC HAL庫代碼部分
在i2c.c文件中可以看到IIC初始化函數(shù)。在stm32f1xx_hal_i2c.h頭文件中可以看到I2C的操作函數(shù)。分別對應(yīng)輪詢,中斷和DMA三種控制方式
上面的函數(shù)看起來多,但是只是發(fā)送和接收的方式改變了,函數(shù)的參數(shù)和本質(zhì)功能并沒有改變
比方說IIC發(fā)送函數(shù) 還是發(fā)送函數(shù),只不過有普通發(fā)送,DMA傳輸,中斷 的幾種發(fā)送模式
這里我們僅介紹下普通發(fā)送,其他的只是改下函數(shù)名即可
IIC寫函數(shù)
HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout);
功能:IIC寫數(shù)據(jù)
參數(shù):
*hi2c 設(shè)置使用的是那個IIC 例:&hi2c2
DevAddress 寫入的地址 設(shè)置寫入數(shù)據(jù)的地址 例 0xA0
*pData 需要寫入的數(shù)據(jù)
Size 要發(fā)送的字節(jié)數(shù)
Timeout 最大傳輸時間,超過傳輸時間將自動退出傳輸函數(shù)
IIC讀函數(shù)
HAL_I2C_Master_Receive(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout);
功能:IIC讀一個字節(jié)
參數(shù):
*hi2c: 設(shè)置使用的是那個IIC 例:&hi2c2
DevAddress: 寫入的地址 設(shè)置寫入數(shù)據(jù)的地址 例 0xA0
*pDat:a 存儲讀取到的數(shù)據(jù)
Size: 發(fā)送的字節(jié)數(shù)
Timeout: 最大讀取時間,超過時間將自動退出讀取函數(shù)
舉例:
HAL_I2C_Master_Transmit(&hi2c1,0xA1,(uint8_t*)TxData,2,1000) ;;
發(fā)送兩個字節(jié)數(shù)據(jù)
IIC寫數(shù)據(jù)函數(shù)
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);
/* 第1個參數(shù)為I2C操作句柄
第2個參數(shù)為從機(jī)設(shè)備地址
第3個參數(shù)為從機(jī)寄存器地址
第4個參數(shù)為從機(jī)寄存器地址長度
第5個參數(shù)為發(fā)送的數(shù)據(jù)的起始地址
第6個參數(shù)為傳輸數(shù)據(jù)的大小
第7個參數(shù)為操作超時時間 */
功能: IIC寫多個數(shù)據(jù) 該函數(shù)適用于IIC外設(shè)里面還有子地址寄存器的設(shè)備,比方說E2PROM,除了設(shè)備地址,每個存儲字節(jié)都有其對應(yīng)的地址
參數(shù):
*hi2c: I2C設(shè)備號指針,設(shè)置使用的是那個IIC 例:&hi2c2
DevAddress: 從設(shè)備地址 從設(shè)備的IIC地址 例E2PROM的設(shè)備地址 0xA0
MemAddress: 從機(jī)寄存器地址 ,每寫入一個字節(jié)數(shù)據(jù),地址就會自動+1
MemAddSize: 從機(jī)寄存器地址字節(jié)長度 8位或16位
寫入數(shù)據(jù)的字節(jié)類型 8位還是16位
I2C_MEMADD_SIZE_8BIT
I2C_MEMADD_SIZE_16BIT
在stm32f1xx_hal_i2c.h中有定義
*pData: 需要寫入的的數(shù)據(jù)的起始地址
Size: 傳輸數(shù)據(jù)的大小 多少個字節(jié)
Timeout: 最大讀取時間,超過時間將自動退出函數(shù)
使用HAL_I2C_Mem_Write等于先使用HAL_I2C_Master_Transmit傳輸?shù)谝粋€寄存器地址,再用HAL_I2C_Master_Transmit傳輸寫入第一個寄存器的數(shù)據(jù)。可以傳輸多個數(shù)據(jù)
void Single_WriteI2C(uint8_t REG_Address,uint8_t REG_data)
{
uint8_t TxData[2] = {REG_Address,REG_data};
while(HAL_I2C_Master_Transmit(&hi2c1,I2C1_WRITE_ADDRESS,(uint8_t*)TxData,2,1000) != HAL_OK)
{
if (HAL_I2C_GetError(&hi2c1) != HAL_I2C_ERROR_AF)
{
Error_Handler();
}
}
}
在傳輸過程,寄存器地址和源數(shù)據(jù)地址是會自加的。
至于讀函數(shù)也是如此,因此用HAL_I2C_Mem_Write和HAL_I2C_Mem_Read,來寫讀指定設(shè)備的指定寄存器數(shù)據(jù)是十分方便的,讓設(shè)計(jì)過程省了好多步驟。
舉例:
8位:
HAL_I2C_Mem_Write(&hi2c2, ADDR, i, I2C_MEMADD_SIZE_8BIT,&(I2C_Buffer_Write[i]),8, 1000);
HAL_I2C_Mem_Read(&hi2c2, ADDR, i, I2C_MEMADD_SIZE_8BIT,&(I2C_Buffer_Write[i]),8, 1000);
16位:
HAL_I2C_Mem_Write(&hi2c2, ADDR, i, I2C_MEMADD_SIZE_16BIT,&(I2C_Buffer_Write[i]),8, 1000);
HAL_I2C_Mem_Read(&hi2c2, ADDR, i, I2C_MEMADD_SIZE_16BIT,&(I2C_Buffer_Write[i]),8, 1000);
如果只往某個外設(shè)中寫數(shù)據(jù),則用Master_Transmit。 如果是外設(shè)里面還有子地址,例如我們的E2PROM,有設(shè)備地址,還有每個數(shù)據(jù)的寄存器存儲地址。則用Mem_Write。
Mem_Write是2個地址,Master_Transmit只有從機(jī)地址
硬件IIC讀取AT24C02
在mian.c文件前面聲明,AT24C02 寫地址和讀地址 ,定義寫數(shù)據(jù)數(shù)組,和讀數(shù)據(jù)數(shù)組
/* USER CODE BEGIN PV */
#include #define ADDR_24LCxx_Write 0xA0 #define ADDR_24LCxx_Read 0xA1 #define BufferSize 256 uint8_t WriteBuffer[BufferSize],ReadBuffer[BufferSize]; uint16_t i; /* USER CODE END PV */ 重新定義printf函數(shù) 在 stm32f4xx_hal.c中包含#include #include "stm32f4xx_hal.h" #include extern UART_HandleTypeDef huart1; //聲明串口 在 stm32f4xx_hal.c 中重寫fget和fput函數(shù) /** * 函數(shù)功能: 重定向c庫函數(shù)printf到DEBUG_USARTx * 輸入?yún)?shù): 無 * 返 回 值: 無 * 說 明:無 */ int fputc(int ch, FILE *f) { HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff); return ch; } /** * 函數(shù)功能: 重定向c庫函數(shù)getchar,scanf到DEBUG_USARTx * 輸入?yún)?shù): 無 * 返 回 值: 無 * 說 明:無 */ int fgetc(FILE *f) { uint8_t ch = 0; HAL_UART_Receive(&huart1, &ch, 1, 0xffff); return ch; } 在main.c中添加 /* USER CODE BEGIN 2 */ for(i=0; i<256; i++) WriteBuffer[i]=i; /* WriteBuffer init */ printf("rn***************I2C Example Z小旋測試*******************************rn"); for (int j=0; j<32; j++) { if(HAL_I2C_Mem_Write(&hi2c1, ADDR_24LCxx_Write, 8*j, I2C_MEMADD_SIZE_8BIT,WriteBuffer+8*j,8, 1000) == HAL_OK) { printf("rn EEPROM 24C02 Write Test OK rn"); HAL_Delay(20); } else { HAL_Delay(20); printf("rn EEPROM 24C02 Write Test False rn"); } } /* // wrinte date to EEPROM 如果要一次寫一個字節(jié),寫256次,用這里的代碼 for(i=0;i HAL_I2C_Mem_Write(&hi2c1, ADDR_24LCxx_Write, i, I2C_MEMADD_SIZE_8BIT,&WriteBuffer[i],1,0xff);//使用I2C塊讀,出錯。因此采用此種方式,逐個單字節(jié)寫入 HAL_Delay(5);//此處延時必加,與AT24C02寫時序有關(guān) } printf("rn EEPROM 24C02 Write Test OK rn"); */ HAL_I2C_Mem_Read(&hi2c1, ADDR_24LCxx_Read, 0, I2C_MEMADD_SIZE_8BIT,ReadBuffer,BufferSize, 0xff); for(i=0; i<256; i++) printf("0x%02X ",ReadBuffer[i]); /* USER CODE END 2 */ 注意事項(xiàng): AT24C02的IIC每次寫之后要延時一段時間才能繼續(xù)寫 每次寫之后要delay 5ms左右 不管硬件IIC采用何種形式(DMA,IT),都要確保兩次寫入的間隔大于5ms; 讀寫函數(shù)最后一個超時調(diào)整為1000以上 因?yàn)槲覀円淮螌?個字節(jié),延時要久一點(diǎn) AT24C02頁寫入只支持8個byte,所以需要分32次寫入。這不是HAL庫的bug,而是AT24C02的限制,其他的EEPROM可以支持更多byte的寫入。 當(dāng)然,你也可以每次寫一個字節(jié),分成256次寫入,也是可以的 那就用注釋了的代碼即可 /* // wrinte date to EEPROM 如果要一次寫一個字節(jié),寫256次,用這里的代碼 for(i=0;i HAL_I2C_Mem_Write(&hi2c1, ADDR_24LCxx_Write, i, I2C_MEMADD_SIZE_8BIT,&WriteBuffer[i],1,0xff);//使用I2C塊讀,出錯。因此采用此種方式,逐個單字節(jié)寫入 HAL_Delay(5);//此處延時必加,與AT24C02寫時序有關(guān) } printf("rn EEPROM 24C02 Write Test OK rn");
上一篇:【STM32】HAL庫 STM32CubeMX教程十三---RTC時鐘
下一篇:【STM32】 DMA原理,步驟超細(xì)詳解,一文看懂DMA
推薦閱讀
史海拾趣
設(shè)計(jì)資源 培訓(xùn) 開發(fā)板 精華推薦
- 【ESP32】通過串口控制直流電機(jī)
- ESP32 spi 驅(qū)動使用 dummy 方式支持設(shè)備驅(qū)動
- ESP32系列CPU支持差分升級
- ESP32驅(qū)動MFRC522 RFID模塊讀寫IC卡數(shù)據(jù)
- 人形機(jī)器人馬拉松背后的思考,兆易創(chuàng)新如何賦能機(jī)器人產(chǎn)業(yè)
- 一種基于STM32的智能柜控制器設(shè)計(jì)
- 小型傾轉(zhuǎn)旋翼機(jī)的無刷直流電機(jī)驅(qū)動器設(shè)計(jì)
- 超高速攝影機(jī)電控系統(tǒng)設(shè)計(jì)
- 基于GPS自動授時的無線智能控制器的設(shè)計(jì)
- 小鵬華為聯(lián)手終結(jié)AR-HUD“三大痛”
- 英特爾攜手香港大學(xué)“菁英聚·港大”,推動中學(xué)人工智能教育普及
- 奔馳,國軒高科固態(tài)電池正式裝車,續(xù)航超1000km!
- 高功耗芯片如何設(shè)計(jì)滿足散熱需求?
- 智能駕駛仿真研究:仿真走向跨域融合,世界模型應(yīng)用提速
- 國投招商投資景略半導(dǎo)體,加速車載芯片國產(chǎn)替代進(jìn)程
- 正極材料知多少:LFP仍是市場主流,三元體系將持續(xù)滲透30萬元以上車型
- 擺脫中國電池鏈?特斯拉欲自建電池生產(chǎn)體系
- 人形機(jī)器人新賽道,湖北想贏
- 大陸集團(tuán)開發(fā)出全新傳感器技術(shù) 可減少稀土元素的使用
- TI 處理器主題月:三場直播精彩這個八月!報(bào)名且看直播就能得好禮!更有提問獎相送!
- 有獎直播|貝能國際推出基于英飛凌技術(shù)的毫米波雷達(dá)模組,完美解決PIR市場痛點(diǎn)
- 有獎直播:安森美汽車熱管理e- Compressor 應(yīng)用
- 快來訪問泰克高速串行通信專題 配置您的專屬解決方案 贏好禮!
- TI 工業(yè)月,靈感不設(shè)限!21天習(xí)慣養(yǎng)成記!打卡贏好禮啦!
- 有獎直播:ADI 慣性 MEMS 傳感器的應(yīng)用價值與選型
- 有獎直播|安森美高能效產(chǎn)品在 EV-Charger 市場的應(yīng)用
- 學(xué)習(xí)贏京東卡 | 從12V電池及供電網(wǎng)絡(luò)優(yōu)化的角度分析電動汽車E/E架構(gòu)的趨勢
- S3C6410存儲器、地址映射與芯片啟動
- s3c2440 地址分配硬件連接及其啟動原理分析
- S3C2440的尋址空間、存儲控制器
- linux中S3C2440的物理地址映射到虛擬地址詳解
- 基于linux2.6.30.4的s3c2440寄存器的虛擬地址和物理地址的關(guān)系
- 國軒高科官宣:磷酸鐵鋰電池單體能量密度已突破200Wh/kg
- 雷諾的微車Twingo ZE和國內(nèi)的A00小車電池
- 5000字長文解讀車載USB供電的方方面面
- 解決所有車輛的CAN總線安全漏洞 UltraSoC推出CAN Sentinel
- Molex發(fā)展下一代車載以太網(wǎng)絡(luò)平臺,實(shí)現(xiàn)完整的車輛生態(tài)系統(tǒng)