打印
[活动专区]

【AT-START-L021测评】0.96寸OLED驱动

[复制链接]
252|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
       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函数中添加了句柄的赋值
OLEDhi2cx.i2cx = I2C1;
       主要是和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)

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

9

主题

57

帖子

0

粉丝