OLED是常见的显示模块,本次是用雅特力AT-START-L021来驱动主控芯片为SSD1306的0.96寸OLED模块,使用的是IIC进行通信。
首先是在新创建的工程中添加i2c_application.c(在BSP文件夹下)和at32l021_i2c.c和at32l021_dma.c(在FIRMWARE文件夹下)。其中at32l021_dma.c在i2c_application.c中引用,但是实际的工程中没有使用到,去掉编译会有问题。
其次是在main函数中调用IIC初始化相关函数,这里参考了IIC例程。在main.c中添加如下的IIC对应的GPIO口初始化函数
void i2c_lowlevel_init(i2c_handle_type* hi2c)
{
gpio_init_type gpio_init_structure;
if(hi2c->i2cx == I2Cx_PORT)
{
/* i2c periph clock enable */
crm_periph_clock_enable(I2Cx_CLK, TRUE);
crm_periph_clock_enable(I2Cx_SCL_GPIO_CLK, TRUE);
crm_periph_clock_enable(I2Cx_SDA_GPIO_CLK, TRUE);
/* gpio configuration */
gpio_pin_mux_config(I2Cx_SCL_GPIO_PORT, I2Cx_SCL_GPIO_PinsSource, I2Cx_SCL_GPIO_MUX);
gpio_pin_mux_config(I2Cx_SDA_GPIO_PORT, I2Cx_SDA_GPIO_PinsSource, I2Cx_SDA_GPIO_MUX);
/* configure i2c pins: scl */
gpio_init_structure.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
gpio_init_structure.gpio_mode = GPIO_MODE_MUX;
gpio_init_structure.gpio_out_type = GPIO_OUTPUT_OPEN_DRAIN;
gpio_init_structure.gpio_pull = GPIO_PULL_NONE;
gpio_init_structure.gpio_pins = I2Cx_SCL_GPIO_PIN;
gpio_init(I2Cx_SCL_GPIO_PORT, &gpio_init_structure);
/* configure i2c pins: sda */
gpio_init_structure.gpio_pins = I2Cx_SDA_GPIO_PIN;
gpio_init(I2Cx_SDA_GPIO_PORT, &gpio_init_structure);
/* config i2c */
i2c_init(hi2c->i2cx, 0x0F, I2Cx_CLKCTRL);
i2c_own_address1_set(hi2c->i2cx, I2C_ADDRESS_MODE_7BIT, I2Cx_ADDRESS);
}
}
在main中添加如下的宏定义
#define I2C_TIMEOUT 0xFFFFFFF
//#define I2Cx_CLKCTRL 0xF070F7F7 //10K
//#define I2Cx_CLKCTRL 0x60F06C6C //50K
#define I2Cx_CLKCTRL 0x60F03333 //100K
//#define I2Cx_CLKCTRL 0x20C02C4F //200K
//#define I2Cx_ADDRESS 0xA0
#define I2Cx_PORT I2C1
#define I2Cx_CLK CRM_I2C1_PERIPH_CLOCK
#define I2Cx_DMA DMA1
#define I2Cx_DMA_CLK CRM_DMA1_PERIPH_CLOCK
#define I2Cx_SCL_GPIO_CLK CRM_GPIOB_PERIPH_CLOCK
#define I2Cx_SCL_GPIO_PIN GPIO_PINS_6
#define I2Cx_SCL_GPIO_PinsSource GPIO_PINS_SOURCE6
#define I2Cx_SCL_GPIO_PORT GPIOB
#define I2Cx_SCL_GPIO_MUX GPIO_MUX_1
#define I2Cx_SDA_GPIO_CLK CRM_GPIOB_PERIPH_CLOCK
#define I2Cx_SDA_GPIO_PIN GPIO_PINS_7
#define I2Cx_SDA_GPIO_PinsSource GPIO_PINS_SOURCE7
#define I2Cx_SDA_GPIO_PORT GPIOB
#define I2Cx_SDA_GPIO_MUX GPIO_MUX_1
在main中添加对应的.h调用代码
#include "i2c_application.h"
main函数中调用IIC初始化的代码如下
hi2cx.i2cx = I2Cx_PORT;
/* i2c config */
i2c_config(&hi2cx);
之后是添加OLED的驱动,这里是参考常用的OLED驱动,只是修改发送数据的代码,OLED.c的代码如下
#include "oled.h"
#include "oledfont.h"
#include "i2c_application.h"
i2c_handle_type OLEDhi2cx;
void OLED_WriteByte(uint8_t data, uint8_t mode);
void OLED_Clear(void);
void OLED_SetPos(uint8_t x, uint8_t y);
void OLED_DrawBMP(uint8_t x, uint8_t y, uint8_t sizex, uint8_t sizey, const uint8_t BMP[]);
/*
函 数 名:OLED_WriteByte
功 能:发送一个字节
参数描述:data:发送数据
mode:模式选择 0:命令 1:数据
返 回 值:无
*/
void OLED_WriteByte(uint8_t data, uint8_t mode)
{
uint8_t u8Senddata[2] = {0};
u8Senddata[0] = mode;
u8Senddata[1] = data;
i2c_master_transmit(&OLEDhi2cx,OLED_ADDR, u8Senddata, 2, 0xFF);
}
/*
函 数 名:OLED_Clear
功 能:清屏
参数描述:无
返 回 值:无
*/
void OLED_Clear(void)
{
uint8_t i,n;
for(i=0; i<OLED_PAGE_SUM; i++)
{
OLED_WriteByte (OLED_REG_PAGE_SET + i,OLED_SEND_CMD); /* 设置页地址(0~7) */
OLED_WriteByte (OLED_REG_LINE_L_SET,OLED_SEND_CMD); /* 设置显示位置—列低地址 */
OLED_WriteByte (OLED_REG_LINE_H_SET,OLED_SEND_CMD); /* 设置显示位置—列高地址 */
for(n=0; n<128; n++)
{
OLED_WriteByte(0,OLED_SEND_DATA);
}//更新显示
}
}
/*
函 数 名:OLED_SetPos
功 能:坐标设置
参数描述:x:横坐标
Y:纵坐标
返 回 值:无
*/
void OLED_SetPos(uint8_t x, uint8_t y)
{
OLED_WriteByte(0xb0 + y, OLED_SEND_CMD);
OLED_WriteByte(((x & 0xf0) >> 4) | 0x10, OLED_SEND_CMD);
OLED_WriteByte((x & 0x0f), OLED_SEND_CMD);
}
/*
函 数 名:OLED_DrawBMP
功 能:显示图片
参数描述:x, y:起始坐标
sizex, sizey:终止坐标
BMP:图像数据
返 回 值:无
*/
void OLED_DrawBMP(uint8_t x, uint8_t y, uint8_t sizex, uint8_t sizey, const uint8_t BMP[])
{
uint16_t j=0;
uint8_t i, m, temp;
sizey = sizey / 8 + ((sizey % 8) ? 1 : 0);
for(i = 0; i < sizey; i++)
{
OLED_SetPos(x, i + y);
for(m = 0; m < sizex; m++)
{
temp = BMP[j++];
OLED_WriteByte(temp, OLED_SEND_DATA);
}
}
}
//屏幕旋转180度
void OLED_DisplayTurn(uint8_t i)
{
if(i==0)
{
OLED_WriteByte(0xC8,OLED_SEND_CMD);//正常显示
OLED_WriteByte(0xA1,OLED_SEND_CMD);
}
else
{
OLED_WriteByte(0xC0,OLED_SEND_CMD);//反转显示
OLED_WriteByte(0xA0,OLED_SEND_CMD);
}
}
/*
函 数 名:OLED_Init
功 能:OLED初始化
参数描述:无
返 回 值:无
*/
void OLED_Init()
{
OLEDhi2cx.i2cx = I2C1;
OLED_WriteByte(0xAE,OLED_SEND_CMD);//--turn off oled panel
OLED_WriteByte(0x00,OLED_SEND_CMD);//---set low column address
OLED_WriteByte(0x10,OLED_SEND_CMD);//---set high column address
OLED_WriteByte(0x40,OLED_SEND_CMD);//--set start line address Set Mapping RAM Display Start Line (0x00~0x3F)
OLED_WriteByte(0x81,OLED_SEND_CMD);//--set contrast control register
OLED_WriteByte(0xCF,OLED_SEND_CMD); // Set SEG Output Current Brightness
OLED_WriteByte(0xA1,OLED_SEND_CMD);//--Set SEG/Column Mapping 0xa0左右反置 0xa1正常
OLED_WriteByte(0xC8,OLED_SEND_CMD);//Set COM/Row Scan Direction 0xc0上下反置 0xc8正常
OLED_WriteByte(0xA6,OLED_SEND_CMD);//--set normal display
OLED_WriteByte(0xA8,OLED_SEND_CMD);//--set multiplex ratio(1 to 64)
OLED_WriteByte(0x3f,OLED_SEND_CMD);//--1/64 duty
OLED_WriteByte(0xD3,OLED_SEND_CMD);//-set display offset Shift Mapping RAM Counter (0x00~0x3F)
OLED_WriteByte(0x00,OLED_SEND_CMD);//-not offset
OLED_WriteByte(0xd5,OLED_SEND_CMD);//--set display clock divide ratio/oscillator frequency
OLED_WriteByte(0x80,OLED_SEND_CMD);//--set divide ratio, Set Clock as 100 Frames/Sec
OLED_WriteByte(0xD9,OLED_SEND_CMD);//--set pre-charge period
OLED_WriteByte(0xF1,OLED_SEND_CMD);//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
OLED_WriteByte(0xDA,OLED_SEND_CMD);//--set com pins hardware configuration
OLED_WriteByte(0x12,OLED_SEND_CMD);
OLED_WriteByte(0xDB,OLED_SEND_CMD);//--set vcomh
OLED_WriteByte(0x40,OLED_SEND_CMD);//Set VCOM Deselect Level
OLED_WriteByte(0x20,OLED_SEND_CMD);//-Set Page Addressing Mode (0x00/0x01/0x02)
OLED_WriteByte(0x02,OLED_SEND_CMD);//
OLED_WriteByte(0x8D,OLED_SEND_CMD);//--set Charge Pump enable/disable
OLED_WriteByte(0x14,OLED_SEND_CMD);//--set(0x10) disable
OLED_WriteByte(0xA4,OLED_SEND_CMD);// Disable Entire Display On (0xa4/0xa5)
OLED_WriteByte(0xA6,OLED_SEND_CMD);// Disable Inverse Display On (0xa6/a7)
OLED_Clear();
OLED_WriteByte(0xAF,OLED_SEND_CMD); /*display ON*/
OLED_DisplayTurn(1);//0正常显示 1翻转180度显示
}
/*
函 数 名:OLED_Init
功 能:OLED初始化
参数描述:无
返 回 值:无
*/
void OLED_Test(void)
{
OLED_DrawBMP(0, 0, 128, 64, BMP1);
}
//在指定位置显示一个字符
//x:0~127
//y:0~63
//sizey:选择字体 6x8 8x16
void OLED_ShowChar(uint8_t x, uint8_t y,const uint8_t chr, uint8_t sizey)
{
uint8_t c = 0, sizex = sizey / 2, temp;
uint16_t i = 0, size1;
if (sizey == 8)
{
size1=6;
}
else
{
size1=(sizey/8+((sizey%8)?1:0))*(sizey/2);
}
c = chr - ' ';//得到偏移后的值
OLED_SetPos(x,y);
for(i = 0; i < size1; i++)
{
if(((i % sizex) == 0) && (sizey != 8))
{
OLED_SetPos(x,y++);
}
if( sizey == 8)
{
temp = asc2_0806[c][i];
OLED_WriteByte(temp,OLED_SEND_DATA);//6X8字号
}
else if(sizey == 16)
{
temp=asc2_1608[c][i];
OLED_WriteByte(temp,OLED_SEND_DATA);//8x16字号
}
else
{
return;
}
}
}
//显示一个字符号串
void OLED_ShowString(uint8_t x, uint8_t y,const char *chr, uint8_t sizey)
{
uint8_t j = 0;
while (chr[j] != '\0')
{
OLED_ShowChar(x, y, chr[j++], sizey);
if(sizey == 8)
{
x+=6;
}
else
{
x += (sizey / 2);
}
}
}
//m^n函数
uint32_t oled_pow(uint8_t m,uint8_t n)
{
uint32_t result=1;
while(n--)result*=m;
return result;
}
//显示数字
//x,y :起点坐标
//num:要显示的数字
//len :数字的位数
//sizey:字体大小
void OLED_ShowNum(unsigned char x,unsigned char y,unsigned int num,unsigned char len,unsigned char sizey)
{
uint8_t t,temp,m=0;
uint8_t enshow=0;
if(sizey==8)m=2;
for(t=0;t<len;t++)
{
temp=(num/oled_pow(10,len-t-1))%10;
if(enshow==0&&t<(len-1))
{
if(temp==0)
{
OLED_ShowChar(x+(sizey/2+m)*t,y,' ',sizey);
continue;
}else enshow=1;
}
OLED_ShowChar(x+(sizey/2+m)*t,y,temp+'0',sizey);
}
}
其中在OLED.c中定义了对应的IIC句柄
i2c_handle_type OLEDhi2cx;
在OLED_Init函数中添加了句柄的赋值
主要是和main函数中初始化的IIC是一个IIC外设。
OLED发送函数使用i2c_application.c中的i2c_master_transmit函数,发送函数定义如下
void OLED_WriteByte(uint8_t data, uint8_t mode)
{
uint8_t u8Senddata[2] = {0};
u8Senddata[0] = mode;
u8Senddata[1] = data;
i2c_master_transmit(&OLEDhi2cx,OLED_ADDR, u8Senddata, 2, 0xFF);
}
引脚连接图如下
实现效果如下
工程文件:
OLEDProject.zip
(2.16 MB)
|
|