使用STM32硬件I2C和DMA驱动OLED显示屏(HAL方式)
硬件I2C开通DMA
使用硬件I2C开通DMA方式来驱动0.96OLED(1306芯片)花了我好几天时间。我猜测主要是因为程序其他方面运行太快了,通过DMA方式来给OLED传输数据跟不上。最后参考了keysking的教学视频,设置了一个状态变量,并且写一个自己的DMA中断处理函数。程序是根据江协科技32课程的源码改的。因为开通了硬件I2C,原来的send_byte,OLED_I2C_Start, OLED_I2C_Stop都不需要了。改写后的OLED_WriteCommand和OLED_WriteData函数如下:
void OLED_WriteCommand(uint8_t Command)
{
static uint8_t sendbuffer[2]; //static this is very important
while (dmastate ==0); //make sure previous data has been sent
sendbuffer[0]=0x00; //写命令
sendbuffer[1]=Command;
HAL_I2C_Master_Transmit_DMA(&hi2c1, 0x78, sendbuffer, 2);
dmastate=0;
}
void OLED_WriteData(uint8_t Data)
{
static uint8_t sendbuffer[2];
while (dmastate == 0);
sendbuffer[0]=0x40; //写数据
sendbuffer[1]=Data;
HAL_I2C_Master_Transmit_DMA(&hi2c1, 0x78, sendbuffer, 2);
dmastate =0;
}
在main.c中声明一个全局变量dmastate,用来控制能否进行新的一次DMA传输
uint8_t dmastate =1; //indicate whether DMA has sent the data
在main.c中还需要写自己的I2C传输完成中断处理函数
void HAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef *hi2c){
if(hi2c == &hi2c1) dmastate =1;
}
在OLED.c中需要新增include和声明两个外部变量
#include "stm32f1xx_hal.h"
extern I2C_HandleTypeDef hi2c1;
extern uint8_t dmastate;
如果不用dmastate和中断函数的话,我测试一下在HAL_I2C_Master_Transmit_DMA后延时10毫秒也行,就是加上HAL_Delay(10),但是OLED屏幕更新太慢了。
硬件I2C没有DMA
对于驱动OLED来说,感觉开通DMA并没有多大益处,但用硬件I2C可以减少很多代码。对江协科技2024年4月的带缓存OLED驱动版本进行了改写。OLED_I2C_Start,OLED_I2C_Stop,OLED_I2C_SendByte这三个函数都用不到了。改写后另外两个函数如下:
void OLED_WriteCommand(uint8_t Command)
{
uint8_t sendbuffer[2]={0x00,0};
sendbuffer[1]= Command;
HAL_I2C_Master_Transmit(&hi2c1, 0x78, sendbuffer, 2, 1000);
}
void OLED_WriteData(uint8_t *Data, uint8_t Count)
{
uint8_t i;
uint8_t sendbuffer[Count+1];
sendbuffer[0]=0x40;
/*循环Count次,进行连续的数据写入*/
for (i = 0; i < Count; i ++)
{
sendbuffer[i+1]=Data[i]; //依次发送Data的每一个数据
}
HAL_I2C_Master_Transmit(&hi2c1, 0x78, sendbuffer, Count+1, 1000);
}
作者:2305_76196590