|
【小华HC32F448测评】关于HC32f448的I2C学习及硬件I2C驱动OLED
[复制链接]
本帖最后由 学学学学学学学 于 2023-8-25 17:24 编辑
- 全局宏定义:
/* Define port and pin for SDA and SCL */
#define I2C_SDA_PORT (GPIO_PORT_D)//类似HAL库的配置
#define I2C_SDA_PIN (GPIO_PIN_00)
#define I2C_SCL_PORT (GPIO_PORT_D)
#define I2C_SCL_PIN (GPIO_PIN_01)
#define I2C_SDA_FUNC (GPIO_FUNC_50) //pin脚功能配置号
#define I2C_SCL_FUNC (GPIO_FUNC_51) //详情见数据手册引脚配置页
/* I2C unit define */
#define I2C_UNIT (CM_I2C2) //硬件I2C地址
#define I2C_FCG (FCG1_PERIPH_I2C2) //开启时钟
/**
* @defgroup I2C_Configuration BSP I2C Configuration
* @{
*/
#define I2C_BAUDRATE (400000UL) //I2C波特率配置
#define I2C_TIMEOUT (0x64U) //
数据手册中说明了 i2c 2 的配置功能号是SDA为50,SCL为51,如果是I2C1 就是48 和49,对应时钟是FG1
- 硬件 I2C的GOIO口配置函数:主要需要看数据手册中关于引脚配置页的引脚功能定义
/**
* @brief I2C_Init0 配置gpio口功能,主要是功能号I2C_SCL_FUNC和SDA_FUNC,要按照数据手册写
* @param
* @retval LL_OK
*/
static void I2C_GPIO_Init(void)
{
stc_gpio_init_t stcGpioInit;
/* Configuration I2C GPIO */
(void)GPIO_StructInit(&stcGpioInit);
(void)GPIO_Init(I2C_SCL_PORT, I2C_SCL_PIN, &stcGpioInit);//初始化gpio
(void)GPIO_Init(I2C_SDA_PORT, I2C_SDA_PIN, &stcGpioInit);
GPIO_SetFunc(I2C_SCL_PORT, I2C_SCL_PIN, I2C_SCL_FUNC);//配置功能为SCL
GPIO_SetFunc(I2C_SDA_PORT, I2C_SDA_PIN, I2C_SDA_FUNC);//SDA
/* Enable I2C Peripheral*/
FCG_Fcg1PeriphClockCmd(I2C_FCG, ENABLE);//开启外设时钟
(void)I2C_Init(I2C_UNIT);//I2C初始化函数
}
- I2C 2初始化函数
/**
* @brief I2C_Init1 配置i2c的波特率,边沿时长,分频系数,总线命令
* @param CM_I2C_TypeDef *I2Cx:I2C1 or I2C2 ,you only need to write a i2c base dar directly
* @retval LL_OK
*/
int32_t I2C_2_Init(CM_I2C_TypeDef *I2Cx)
{
int32_t i32Ret;
float32_t fErr;
stc_i2c_init_t stcI2cInit;
I2C_DeInit(I2Cx);
(void)I2C_StructInit(&stcI2cInit);
stcI2cInit.u32Baudrate = I2C_BAUDRATE;
stcI2cInit.u32SclTime = 0U;
stcI2cInit.u32ClockDiv = I2C_CLK_DIV2;
i32Ret = I2C_Init(I2Cx, &stcI2cInit, &fErr);
if (LL_OK == i32Ret) {
I2C_BusWaitCmd(I2Cx, ENABLE);
}
I2C_Cmd(I2Cx, ENABLE);
return i32Ret;
}
- main函数
/**
* @brief Main function
* @param None
*/
int32_t main(void)
{
/* Unlock peripherals or registers */
LL_PERIPH_WE(LL_PERIPH_ALL);
/* Initialize BSP system clock. */
// BSP_CLK_Init();不要取消这行注释,时钟冲突了
/* Initialize BSP expand IO. */
BSP_IO_Init();//也把SDA和SCL初始化成功了
/* Initialize BSP LED. */
BSP_LED_Init();
/* Initialize DDL_Printf */
DDL_PrintfInit(BSP_PRINTF_DEVICE, BSP_PRINTF_BAUDRATE, BSP_PRINTF_Preinit);
/* Initialize I2C2 */
I2C_GPIO_Init();
LED_Init();
oled_init();
/* Peripheral registers write protected */
LL_PERIPH_WP(LL_PERIPH_ALL);
oled_cls();
DDL_DelayMS(200);
for (;;) {
//oled_cls();
//显示一个汉字标题,如果没有oledfont中没有title数组,就换显示个字符串或数组的函数
show_title();
//DDL_DelayMS(50UL);
// LED_G_TOGGLE();
// BSP_LED_Toggle(LED_YELLOW);
// DDL_Printf("advance\n");
}
}
- oled.c和oled.h文件中I2C的驱动程序函数
#include "oledfont.h"
#include "oled.h"
#include "hc32_ll_i2c.h"//很重要的头文件,I2C_trans等函数的来源
/**
* @defgroup I2C_Configuration
* @{
*/
#define I2C_BAUDRATE (400000UL) //I2C波特率配置
#define I2C_TIMEOUT (0x64U) //
#define OLED_ADD (0x3c) //写入OLED初始地址
#define DATA_Len (0x02) //写入数据长度
#define I2C_DIR_TX2 (0x00) //写入标志
/**
* @brief OLED_WR_Byte 写入一字节/两字节
* @param *dat
* @retval 返回 LL_OK
*用法举例:OLED_WR_Byte(buf),buf定义:可定义为数组,如 int8_t buf[2];
*/
int32_t OLED_WR_Byte(uint8_t *dat)
{
int32_t i32Ret;
I2C_SWResetCmd(I2C_UNIT,ENABLE);//I2C复位
I2C_SWResetCmd(I2C_UNIT,DISABLE);
i32Ret = I2C_Start(I2C_UNIT, I2C_TIMEOUT);//启动I2C
if(LL_OK==i32Ret)
{
//写入基地址
i32Ret=I2C_TransAddr(I2C_UNIT,(uint8_t)OLED_ADD,I2C_DIR_TX2,I2C_TIMEOUT );
if(LL_OK==i32Ret)
{
//写入指令数据,这里DATA_Len=2,一次性传输 *dat 两个数据过去,第一个数据是固定寄存器地址,一
//个是实时指令
i32Ret=I2C_TransData(I2C_UNIT,dat,DATA_Len ,I2C_TIMEOUT );
//如果把寄存器地址和数据指令两个字节分开传输,就解出这几行注释,上面先传寄存器地址,下面这几行传
//数据
// if(LL_OK==i32Ret)
// {
// i32Ret=I2C_TransData(I2C_UNIT,dat,DATA_Len ,I2C_TIMEOUT );
// }
}
// if(LL_OK != i32Ret)
// {
// (void)I2C_Stop(BSP_TCA9539_I2C_UNIT,100);
// I2C_SWResetCmd(BSP_TCA9539_I2C_UNIT,ENABLE);
// I2C_SWResetCmd(BSP_TCA9539_I2C_UNIT,DISABLE);
// }
}
(void)I2C_Stop(I2C_UNIT,I2C_TIMEOUT );
return i32Ret;
}
/**
* @brief oled_cmd 写入oled指令
* @param i2c_cmd,一个8位无符号整数
* @retval void
*/
static void oled_cmd(uint8_t i2c_cmd)
{
uint8_t u8TXBuf[2];
u8TXBuf[0]=0x00;
u8TXBuf[1]=i2c_cmd;
OLED_WR_Byte(u8TXBuf);
// uint8_t *cmd;
// uint8_t adr1;
// uint8_t *adr;
// adr1=0x00;
// adr=&adr1;
// cmd=&i2c_cmd;
// BSP_I2C_Write(BSP_TCA9539_I2C_UNIT, OLED_ADD, adr,1,cmd, 1);
}
/**
* @brief oled_data�
* @param i2c_data 传数据
* @retval
*/
static void oled_data(uint8_t i2c_data)
{
uint8_t u8TXBuf[2];
u8TXBuf[0]=0x40;
u8TXBuf[1]=i2c_data;
OLED_WR_Byte(u8TXBuf);
// uint8_t *dat;
// uint8_t adr1;
// uint8_t *adr;
// adr1=0x40;
// adr=&adr1;
// dat=&i2c_data;
// BSP_I2C_Write(BSP_TCA9539_I2C_UNIT, OLED_ADD,adr ,1,dat, 1);
}
- oled初始化
/**
* @brief oled_init 初始化oled
* @param
* @retval
*/
void oled_init(void)
{
DDL_DelayMS(800);
oled_cmd(0xAE); //display off
oled_cmd(0x20); //Set Memory Addressing Mode
oled_cmd(0x10); //00,Horizontal Addressing Mode;01,Vertical Addressing Mode;10,Page Addressing Mode (RESET);11,Invalid
oled_cmd(0xb0); //Set Page Start Address for Page Addressing Mode,0-7
oled_cmd(0xc8); //Set COM Output Scan Direction
oled_cmd(0x00); //---set low column address
oled_cmd(0x10); //---set high column address
oled_cmd(0x40); //--set start line address
oled_cmd(0x81); //--set contrast control register
oled_cmd(0xff); // 0x00~0xff
oled_cmd(0xa1); //--set segment re-map 0 to 127
oled_cmd(0xa6); //--set normal display
oled_cmd(0xa8); //--set multiplex ratio(1 to 64)
oled_cmd(0x3F); //
oled_cmd(0xa4); //0xa4,Output follows RAM content;0xa5,Output ignores RAM content
oled_cmd(0xd3); //-set display offset
oled_cmd(0x00); //-not offset
oled_cmd(0xd5); //--set display clock divide ratio/oscillator frequency
oled_cmd(0xf0); //--set divide ratio
oled_cmd(0xd9); //--set pre-charge period
oled_cmd(0x22); //
oled_cmd(0xda); //--set com pins hardware configuration
oled_cmd(0x12);
oled_cmd(0xdb); //--set vcomh
oled_cmd(0x20); //0x20,0.77xVcc
oled_cmd(0x8d); //--set DC-DC enable
oled_cmd(0x14); //
oled_cmd(0xaf); //--turn on oled panel
}
效果:
其他主要的文件和函数放在附件里了,有需要可看
|
|