- #include "hal_i2c.h"
- #include "delay.h"
- //设置SDA输入模式
- void SDA_IN(void)
- {
- gpio_init_type gpio_init_struct;
-
- //根据GPIO组初始化GPIO时钟
- crm_periph_clock_enable(SDA_GPIO_CRM_CLK, TRUE); //使能GPIOF时钟
- gpio_init_struct.gpio_pins = SDA_PIN;
- gpio_init_struct.gpio_mode = GPIO_MODE_INPUT;
- gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
- gpio_init_struct.gpio_pull = GPIO_PULL_UP;
- gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
- gpio_init(SDA_GPIO, &gpio_init_struct);
- }
- //设置SDA为输出模式
- void SDA_OUT(void)
- {
- gpio_init_type gpio_init_struct;
-
- //根据GPIO组初始化GPIO时钟
- crm_periph_clock_enable(SDA_GPIO_CRM_CLK, TRUE); //使能GPIOF时钟
- gpio_init_struct.gpio_pins = SDA_PIN;
- gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
- gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
- gpio_init_struct.gpio_pull = GPIO_PULL_UP;
- gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
- gpio_init(SDA_GPIO, &gpio_init_struct);
- }
- //设置SCL电平
- void I2C_SCL(int n)
- {
- if(n == 1)
- {
- gpio_bits_write(SCL_GPIO, SCL_PIN, TRUE); //设置SCL为高电平
- }
- else
- {
- gpio_bits_write(SCL_GPIO, SCL_PIN, FALSE); //设置SCL为低电平
- }
- }
- //设置SDA电平
- void I2C_SDA(int n)
- {
- if(n == 1)
- {
- gpio_bits_write(SDA_GPIO, SDA_PIN, TRUE); //设置SDA为高电平
- }
- else
- {
- gpio_bits_write(SDA_GPIO, SDA_PIN, FALSE); //设置SDA为低电平
- }
- }
- //读取SDA电平
- unsigned char READ_SDA(void)
- {
- return gpio_input_data_bit_read(SDA_GPIO, SDA_PIN); //读取SDA电平
- }
- //I2C初始化
- void I2C_Init(void)
- {
- gpio_init_type gpio_init_struct;
-
- //根据GPIO组初始化GPIO时钟
- crm_periph_clock_enable(SCL_GPIO_CRM_CLK, TRUE); //使能GPIOF时钟
- crm_periph_clock_enable(SDA_GPIO_CRM_CLK, TRUE); //使能GPIOF时钟
-
- //GPIO_SCL初始化设置
- gpio_init_struct.gpio_pins = SCL_PIN;
- gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT; //gpio output mode
- gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL; //output push-pull
- gpio_init_struct.gpio_pull = GPIO_PULL_UP; //pull-up
- gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER; //stronger sourcing/sinking strength
- gpio_init(SCL_GPIO, &gpio_init_struct);
- //GPIO_SDA初始化设置
- gpio_init_struct.gpio_pins = SDA_PIN;
- gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
- gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
- gpio_init_struct.gpio_pull = GPIO_PULL_UP;
- gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
- gpio_init(SDA_GPIO, &gpio_init_struct);
- //SCL、SDA的初始化均为高电平
- I2C_SCL(1);
- I2C_SDA(1);
- }
- //I2C Start
- void I2C_Start(void)
- {
- SDA_OUT();
- I2C_SDA(1);
- I2C_SCL(1);
- Delay_Us(4);
- I2C_SDA(0); //START:when CLK is high,DATA change form high to low
- Delay_Us(4);
- I2C_SCL(0); //钳住I2C总线,准备发送或接收数据
- }
- //I2C Stop
- void I2C_Stop(void)
- {
- SDA_OUT();
- I2C_SCL(0);
- I2C_SDA(0); //STOP:when CLK is high DATA change form low to high
- Delay_Us(4);
- I2C_SCL(1);
- I2C_SDA(1); //发送I2C总线结束信号
- Delay_Us(4);
- }
- //I2C_Wait_ack 返回HAL_OK表示wait成功,返回HAL_ERROR表示wait失败
- unsigned char I2C_Wait_Ack(void) //IIC_Wait_ack,返回wait失败或是成功
- {
- unsigned char ucErrTime = 0;
-
- SDA_IN();
- I2C_SDA(1);
- Delay_Us(1);
- I2C_SCL(1);
- Delay_Us(1);
- while(READ_SDA())
- {
- ucErrTime++;
- if(ucErrTime>250)
- {
- I2C_Stop();
- return HAL_ERROR;
- }
- }
- I2C_SCL(0);
- return HAL_OK;
- }
- //产生ACK应答
- void I2C_Ack(void)
- {
- I2C_SCL(0);
- SDA_OUT();
- I2C_SDA(0);
- Delay_Us(2);
- I2C_SCL(1);
- Delay_Us(2);
- I2C_SCL(0);
- }
- //产生NACK应答
- void I2C_NAck(void)
- {
- I2C_SCL(0);
- SDA_OUT();
- I2C_SDA(1);
- Delay_Us(2);
- I2C_SCL(1);
- Delay_Us(2);
- I2C_SCL(0);
- }
- //I2C_Send_Byte,入口参数为要发送的字节
- void I2C_Send_Byte(unsigned char txd)
- {
- unsigned char cnt = 0;
-
- SDA_OUT();
- I2C_SCL(0);
- for(cnt = 0; cnt < 8; cnt++)
- {
- I2C_SDA((txd & 0x80) >> 7);
- txd <<= 1;
- Delay_Us(2);
- I2C_SCL(1);
- Delay_Us(2);
- I2C_SCL(0);
- Delay_Us(2);
- }
- }
- //I2C_Read_Byte,入口参数为是否要发送ACK信号
- unsigned char I2C_Read_Byte(unsigned char ack)
- {
- unsigned char cnt, rec = 0;
-
- SDA_IN();
- for(cnt = 0; cnt < 8; cnt++)
- {
- I2C_SCL(0);
- Delay_Us(2);
- I2C_SCL(1);
- rec <<= 1;
- if(READ_SDA())
- {
- rec++;
- }
- Delay_Us(1);
- }
- if(!ack)
- {
- I2C_NAck();
- }
- else
- {
- I2C_Ack();
- }
- return rec;
- }
hal_0.96oled.c代码:
- #include "hal_0.96oled.h"
- #include "oledfont.h"
- #include "delay.h"
- //向设备写控制命令
- static void OLED_Write_CMD(unsigned char cmd)
- {
- I2C_Start();
- I2C_Send_Byte(0x78);
- I2C_Wait_Ack();
- I2C_Send_Byte(0x00);
- I2C_Wait_Ack();
- I2C_Send_Byte(cmd);
- I2C_Wait_Ack();
- I2C_Stop();
- }
- //向设备写数据
- static void OLED_Write_Date(unsigned char date)
- {
- I2C_Start();
- I2C_Send_Byte(0x78);
- I2C_Wait_Ack();
- I2C_Send_Byte(0x40);
- I2C_Wait_Ack();
- I2C_Send_Byte(date);
- I2C_Wait_Ack();
- I2C_Stop();
- }
- //坐标设置
- static void OLED_Set_Pos(unsigned char x, unsigned char y)
- {
- OLED_Write_CMD(0xB0 + y);
- OLED_Write_CMD(((x & 0xF0) >> 4) | 0x10);
- OLED_Write_CMD(x & 0x0F);
- }
- //开启OLED显示
- static void OLED_Display_On(void)
- {
- OLED_Write_CMD(0x8D); //SET DCDC命令
- OLED_Write_CMD(0x14); //DCDC ON
- OLED_Write_CMD(0xAF); //DISPLAY ON
- }
- //关闭OLED显示
- static void OLED_Display_Off(void)
- {
- OLED_Write_CMD(0x8D); //SET DCDC命令
- OLED_Write_CMD(0x10); //DCDC OFF
- OLED_Write_CMD(0xAE); //DISPLAY OFF
- }
- //OLED清屏
- void OLED_Clear(void)
- {
- unsigned char cnt, count;
-
- for(cnt = 0; cnt < 8; cnt++)
- {
- OLED_Write_CMD(0xB0 + cnt);
- OLED_Write_CMD(0x00);
- OLED_Write_CMD(0x10);
- for(count = 0; count < 128; count++)
- {
- OLED_Write_Date(0x00);
- }
- }
- }
- //OLED清行
- void OLED_Clear_Row(unsigned char n)
- {
- unsigned char count;
-
- OLED_Write_CMD(0xB0 + n);
- OLED_Write_CMD(0x00);
- OLED_Write_CMD(0x10);
- for(count = 0; count < 128; count++)
- {
- OLED_Write_Date(0x00);
- }
- }
- //OLED填满屏幕
- void OLED_Fill(void)
- {
- unsigned char cnt, count;
-
- for(cnt = 0; cnt < 8; cnt++)
- {
- OLED_Write_CMD(0xB0 + cnt); //设置页地址(0~7)
- OLED_Write_CMD(0x00); //设置显示位置—列低地址
- OLED_Write_CMD(0x10); //设置显示位置—列高地址
- for(count = 0; count < 128; count++)
- {
- OLED_Write_Date(0x01);
- }
- }
- }
- //指定位置显示一个字符
- //x:0~127
- //y:0~63
- //chr:字符
- //mode:0,反白显示;1,正常显示
- //size:选择字体 16/12
- void OLED_ShowChar(unsigned char x, unsigned char y, unsigned char chr, unsigned char size)
- {
- unsigned char offset = 0, cnt = 0;
-
- offset = chr - ' '; //计算偏移量
- if(x > 128 - 1)
- {
- x = 0;
- y = y + 2;
- }
- if(size == 16)
- {
- OLED_Set_Pos(x, y);
- for(cnt = 0; cnt < 8; cnt++)
- {
- OLED_Write_Date(F8x16[offset * 16 + cnt]);
- }
- OLED_Set_Pos(x, y + 1);
- for(cnt = 0; cnt < 8; cnt++)
- {
- OLED_Write_Date(F8x16[offset * 16 + cnt + 8]);
- }
- }
- else
- {
- OLED_Set_Pos(x, y);
- for(cnt = 0; cnt < 6; cnt++)
- {
- OLED_Write_Date(F6x8[offset][cnt]);
- }
- }
- }
- unsigned int oled_pow(unsigned char m, unsigned char n)
- {
- unsigned int result = 1;
- while(n--)
- {
- result *= m;
- }
- return result;
- }
- //指定位置显示一个数字
- //x,y:起点坐标
- //num:数值(0~4294967295)
- //len:数字的位数
- //size:字体大小
- //mode:模式 0,填充模式;1,叠加模式
- void OLED_ShowNum(unsigned char x, unsigned char y, unsigned int num, unsigned char len, unsigned char size)
- {
- unsigned char cnt, temp;
- unsigned char show = 0;
-
- for(cnt = 0; cnt < len; cnt++)
- {
- temp = (num / oled_pow(10, len - cnt - 1)) % 10;
- if(show == 0 && cnt < (len - 1))
- {
- if(temp == 0)
- {
- OLED_ShowChar(x + (size / 2) * cnt, y, ' ', size);
- continue;
- }
- else
- {
- show = 1;
- }
- }
- OLED_ShowChar(x + (size / 2) * cnt, y, temp + '0', size);
- }
- }
- //指定位置显示字符串
- void OLED_ShowString(unsigned char x, unsigned char y, unsigned char *chr, unsigned char size)
- {
- unsigned char cnt = 0;
-
- while(chr[cnt] != '\0')
- {
- OLED_ShowChar(x, y, chr[cnt], size);
- x += 8;
- if(x > 120)
- {
- x = 0;
- y += 2;
- }
- cnt++;
- }
- }
- //显示汉字
- void OLED_ShowCHinese(unsigned char x, unsigned char y, unsigned char no)
- {
- unsigned char cnt, addr = 0;
-
- OLED_Set_Pos(x, y);
- for(cnt = 0; cnt < 16; cnt++)
- {
- OLED_Write_Date(Hzk[2 * no][cnt]);
- addr++;
- }
- OLED_Set_Pos(x, y + 1);
- for(cnt = 0; cnt < 16; cnt++)
- {
- OLED_Write_Date(Hzk[2 * no + 1][cnt]);
- addr++;
- }
- }
- //OLED初始化
- void OLED_Init(void)
- {
- I2C_Init();
- Delay_Ms(200);
- OLED_Write_CMD(0xAE); //display off
- OLED_Write_CMD(0x00); //set low column address
- OLED_Write_CMD(0x10); //set high column address
- OLED_Write_CMD(0x40); //set start line address
- OLED_Write_CMD(0xB0); //set page address
- OLED_Write_CMD(0x81); //contract control
- OLED_Write_CMD(0xFF); //128
- OLED_Write_CMD(0xA1); //set segment remap
- OLED_Write_CMD(0xA6); //normal / reverse
- OLED_Write_CMD(0xA8); //set multiplex ratio(1 to 64)
- OLED_Write_CMD(0x3F); //1/32 duty
- OLED_Write_CMD(0xC8); //Com scan direction
- OLED_Write_CMD(0xD3); //set display offset
- OLED_Write_CMD(0x00); //
- OLED_Write_CMD(0xD5); //set osc division
- OLED_Write_CMD(0x80); //
- OLED_Write_CMD(0xD8); //set area color mode off
- OLED_Write_CMD(0x05); //
- OLED_Write_CMD(0xD9); //Set Pre-Charge Period
- OLED_Write_CMD(0xF1); //
- OLED_Write_CMD(0xDA); //set com pin configuartion
- OLED_Write_CMD(0x12); //
- OLED_Write_CMD(0xDB); //set Vcomh
- OLED_Write_CMD(0x30); //
- OLED_Write_CMD(0x8D); //set charge pump enable
- OLED_Write_CMD(0x14); //
- OLED_Write_CMD(0xAF); //turn on oled panel
- }
模拟i2c时,delay.c代码:
- #include "at32f425.h"
- #include "hal_timer.h"
- static unsigned char fac_us = 0; //us延时倍乘数
- static unsigned short fac_ms = 0; //ms延时倍乘数
- //初始化延迟函数
- //SYSTICK的时钟固定为HCLK时钟的1/8
- //SYSCLK:系统时钟
- void Delay_Init(void)
- {
- crm_clocks_freq_get(&crm_clocks_freq_struct);
- fac_us = crm_clocks_freq_struct.sclk_freq / (8000000U); //systick为HCLK/8,fac_us为systick的1/8/1000000,即每1us systick的VAL减的数目
- fac_ms = (unsigned short)fac_us * (1000U); //每1ms需要的systick时钟数,即每1ms systick的VAL减的数目
- }
- //延时nus
- //nus为要延时的us数
- void Delay_Us(unsigned int nus)
- {
- unsigned int temp;
- SysTick->LOAD = (unsigned int)(nus * fac_us); //时间加载
- SysTick->VAL = 0x00; //清空计数器
- SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; //开始倒数
- do
- {
- temp = SysTick->CTRL;
- }
- while((temp & 0x01) && !(temp & (1 << 16))); //等待时间到达
- SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; //关闭计数器
- SysTick->VAL = 0x00; //清空计数器
- }
- //延时nms
- //注意nms的范围
- //SysTick->LOAD为24位寄存器,所以,最大延时为:
- //nms<=0xffffff*8*1000/SYSCLK
- //SYSCLK单位为Hz,nms单位为ms
- //对96M条件下,nms<=1398
- void Delay_Ms(unsigned short nms)
- {
- unsigned int temp;
- SysTick->LOAD = (unsigned int)(nms * fac_ms); //时间加载(SysTick->LOAD为24bit)
- SysTick->VAL = 0x00; //清空计数器
- SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; //开始倒数
- do
- {
- temp = SysTick->CTRL;
- }
- while((temp & 0x01) && !(temp & (1 << 16))); //等待时间到达,看CTRL的第16位(COUNTFLAG)是否为1,看STRL的第0位(ENABLE)是否为1
- SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; //关闭计数器
- SysTick->VAL = 0x00; //清空计数器
- }
4、显示效果:
5、工程代码: