本文以Nucleo板做主控电路,通过模拟I2C接收BH1750的数据,然后用Cube配置的硬件I2C发送到OLED上显示出来。
, E0 ^: \' S( u& }3 u# c1 v4 w( t# g
5 e9 c( n9 {1 z+ c/ R首先用CubeMX搭建工程& j! u% Z" D& Q
1、/ R' E8 z. ]3 ~3 L# _* }2 x
硬件I2C选择使用I2C2,. D5 E8 M& Q2 R0 J8 Z8 V
/ q; j, _9 N5 |- c% _6 E) \! G% o/ _2 e
模拟I2C用PB5做SDA、PB6做SCL。9 K Z) |) _, ]
9 F$ _" C& f9 p" q$ @+ v8 ]* x. z5 B4 b+ K4 ~
2、0 B: [, ^. d- `
硬件I2C配置,将速度模式选为Fast Mode,频率选为最高400KHz,其它都可以保持默认。
) N! B' v$ K5 Z) r# z9 K- Z2 @
# T5 M3 V, ?% [6 i ?9 c" z
, ]# K% Q! z: v- s9 W ?模拟I2C是配置GPIO,PB5、6配置是一样的,IO需要配置为开漏输出。除了PB5、6其它的IO不用理会。
4 ]' V5 z4 V: X
, N) l5 b+ l5 I a+ K$ w
' t* ~' y$ m% L$ S4 x然后编写代码
. w& y/ }9 G0 r2 ~: @+ Y3、oled.c文件
5 Z3 E$ L; o3 {/ _- M: B这里硬件I2C,是用HAL_I2C_Mem_Write函数写入I2C。
9 _% ~' p! i& g7 @4 {hi2c2:是你自己使用的具体哪个I2C,一般会自动生成,在i2c.c中的初始定义中可以找到; }# Y' G4 G E& {
OLED_SLAVE_ADDRESS:设备的地址 即oled屏幕的地址,具体看厂家的说明,在给的驱动代码中应该是可以找到的;- g0 r6 j* V* b6 F% a- e
3 y' F% S- F) |; Q# ~OLED_dat_ADDRESS:设备内部地址,可以参考原驱动代码。这个函数这里是写入寄存器;
$ A; C1 B& i. x- [- f5 EI2C_MEMADD_SIZE_8BIT:设备内部地址编址方式,根据设备决定是8位编址或者16位编址方式; 这个参数的填写有两种 I2C_MEMADD_SIZE_8BIT I2C_MEMADD_SIZE_16BIT,可以在库代码中找到具体定义;
+ Y& L; T0 k9 `. J/ @7 mdat:写入的数据;
; s! R8 k$ z8 E! H2 z' n1:写入的字节大小;2 `4 i- j0 r! p( v# `: |
I2C2_TIMEOUT_MAX:超时时间。* M" x! F0 F, t$ T# j0 M y r+ ~* c
- /*0 C9 u6 I- O3 m
- * 函数功能: 通过硬件I2C向OLED写入命令或数据
3 s# s! T* U2 Q - * 输入参数: dat 数据,cmd 命令
6 l1 q' t5 l: b$ t - * 返 回 值: 无6 r" C4 O, v! I9 e
- * 说 明:无7 o+ Z* b9 y; S/ U
- */% Y+ v% U: o' @4 \
- void OLED_WR_Byte(unsigned char dat,unsigned char cmd)
B$ v0 h) e2 \7 U - {
; V3 g# v: Y: h) D' b! M - if(cmd) {HAL_I2C_Mem_Write(&hi2c2,OLED_SLAVE_ADDRESS,OLED_dat_ADDRESS,I2C_MEMADD_SIZE_8BIT,&dat,1,I2C2_TIMEOUT_MAX);}! U$ _! u# g# G# S0 b
- else {HAL_I2C_Mem_Write(&hi2c2,OLED_SLAVE_ADDRESS,OLED_cmd_ADDRESS,I2C_MEMADD_SIZE_8BIT,&dat,1,I2C2_TIMEOUT_MAX);}
+ c$ x _' R) z* c. H) T _ - }
复制代码 4、i2c.c文件
' D& B7 z4 v, N+ q% |6 q; x+ M, D模拟I2C的代码我是写在i2c.c文件的最后面,具体代码我这里就不贴出来了。4 `' Y- C9 Y6 T# m
- #define I2C_SCL_HIGH() HAL_GPIO_WritePin(I2Cx_SCL_GPIO_Port,I2Cx_SCL_Pin,GPIO_PIN_SET) // 输出高电平
: k( g& G/ O' M' [3 X; c1 n5 O% ? - #define I2C_SCL_LOW() HAL_GPIO_WritePin(I2Cx_SCL_GPIO_Port,I2Cx_SCL_Pin,GPIO_PIN_RESET)// 输出低电平2 u4 z5 K$ o$ b# d: O0 W
- #define I2C_SDA_HIGH() HAL_GPIO_WritePin(I2Cx_SDA_GPIO_Port,I2Cx_SDA_Pin,GPIO_PIN_SET) // 输出高电平
1 x& y# s* R+ O3 o, g7 s - #define I2C_SDA_LOW() HAL_GPIO_WritePin(I2Cx_SDA_GPIO_Port,I2Cx_SDA_Pin,GPIO_PIN_RESET)// 输出低电平" C! x' H! D1 a$ [% {! m
- #define I2C_SDA_READ() HAL_GPIO_ReadPin(I2Cx_SDA_GPIO_Port,I2Cx_SDA_Pin)
复制代码 & a( ~1 t( A u) k- ~
' }( G. m9 U* T5 u$ r
最后放张实物图
4 [2 Q* t0 I5 s" o* ?0 L
) ^, M3 x, E# Q5 q( W- @9 u
|
能再说一点吗,求教STM32的GPIO是变量,是怎么让I2C模拟更好的呢?
你想想如果需要多通道I2C,而且任意脚位。。。那么你是不是每次都要搞一套I2C的命名,然后各自宏定义,但是,GPIO是变量,变量是啥意思,就是可以赋值,就可以把GPIO的脚位赋值给变量,那么只需要实现一套I2C,然后切换,或者多通道的时候,只需要赋值不同的GPIO不就可以啦!!!当然了,这还涉及到GPIO控制寄存器,是一样的。。。
评分
查看全部评分