416|4

12

帖子

0

资源

一粒金砂(中级)

【RISC-V MCU CH32V103测评】SPI驱动OLED液晶显示屏 [复制链接]

写在前面:前段时间把手头OLED液晶显示屏的驱动写完了,正好看到测评有个网友@bigbat一直没有调试出来,这里放出我编写的代码帮助网友解惑,同时也能完成我的SPI测评真是一举两得。

1、SPI接口的OLED屏,128*64的大小,控制芯片同样是SSD1306

2、引脚配置如下

//========================================
//              GND    电源地
//              VCC  接5V或3.3v电源
//              D0   接PA5(SCL)
//              D1   接PA7(SDA)
//              RES  接PB0
//              DC   接PB1
//              CS   接PA4
//========================================

3、直接上效果图

微信图片_20210210223152.jpg

4、SSD1306液晶初始化函数以及用到的IO口函数的一些初始化,注意中间的延时操作。

首先报保证时钟的准确性,还有延时函数的准确性,因为这里的SPI用的不是片内资源,用的是模拟的SPI。

//初始化SSD1306
void OLED_Init(void)
{
    GPIO_InitTypeDef  GPIO_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);    //使能A端口时钟
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_7;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;         //推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//速度50MHz
    GPIO_Init(GPIOA, &GPIO_InitStructure);    //初始化GPIOD3,6
    GPIO_SetBits(GPIOA,GPIO_Pin_5|GPIO_Pin_7|GPIO_Pin_4);

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);    //使能A端口时钟
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_8;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;         //推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//速度50MHz
    GPIO_Init(GPIOB, &GPIO_InitStructure);    //初始化GPIOD3,6
    GPIO_SetBits(GPIOB,GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_8);

    OLED_RST_Set();
    Delay_Ms(100);
    OLED_RST_Clr();
    Delay_Ms(200);
    OLED_RST_Set();

    OLED_WR_Byte(0xAE,OLED_CMD);//--turn off oled panel
    OLED_WR_Byte(0x02,OLED_CMD);//---set low column address
    OLED_WR_Byte(0x10,OLED_CMD);//---set high column address
    OLED_WR_Byte(0x40,OLED_CMD);//--set start line address  Set Mapping RAM Display Start Line (0x00~0x3F)
    OLED_WR_Byte(0x81,OLED_CMD);//--set contrast control register
    OLED_WR_Byte(0xCF,OLED_CMD); // Set SEG Output Current Brightness
    OLED_WR_Byte(0xA1,OLED_CMD);//--Set SEG/Column Mapping     0xa0左右反置 0xa1正常
    OLED_WR_Byte(0xC8,OLED_CMD);//Set COM/Row Scan Direction   0xc0上下反置 0xc8正常
    OLED_WR_Byte(0xA6,OLED_CMD);//--set normal display
    OLED_WR_Byte(0xA8,OLED_CMD);//--set multiplex ratio(1 to 64)
    OLED_WR_Byte(0x3f,OLED_CMD);//--1/64 duty
    OLED_WR_Byte(0xD3,OLED_CMD);//-set display offset   Shift Mapping RAM Counter (0x00~0x3F)
    OLED_WR_Byte(0x00,OLED_CMD);//-not offset
    OLED_WR_Byte(0xd5,OLED_CMD);//--set display clock divide ratio/oscillator frequency
    OLED_WR_Byte(0x80,OLED_CMD);//--set divide ratio, Set Clock as 100 Frames/Sec
    OLED_WR_Byte(0xD9,OLED_CMD);//--set pre-charge period
    OLED_WR_Byte(0xF1,OLED_CMD);//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
    OLED_WR_Byte(0xDA,OLED_CMD);//--set com pins hardware configuration
    OLED_WR_Byte(0x12,OLED_CMD);
    OLED_WR_Byte(0xDB,OLED_CMD);//--set vcomh
    OLED_WR_Byte(0x40,OLED_CMD);//Set VCOM Deselect Level
    OLED_WR_Byte(0x20,OLED_CMD);//-Set Page Addressing Mode (0x00/0x01/0x02)
    OLED_WR_Byte(0x02,OLED_CMD);//
    OLED_WR_Byte(0x8D,OLED_CMD);//--set Charge Pump enable/disable
    OLED_WR_Byte(0x14,OLED_CMD);//--set(0x10) disable
    OLED_WR_Byte(0xA4,OLED_CMD);// Disable Entire Display On (0xa4/0xa5)
    OLED_WR_Byte(0xA6,OLED_CMD);// Disable Inverse Display On (0xa6/a7)
    OLED_WR_Byte(0xAF,OLED_CMD);//--turn on oled panel
    OLED_WR_Byte(0xAF,OLED_CMD); /*display ON*/
    OLED_Clear();
    OLED_Set_Pos(0,0);
}

5、模拟SPI收发数据函数驱动如下,一定要注意延时要准确

//向SSD1306写入一个字节。
//dat:要写入的数据/命令
//cmd:数据/命令标志 0,表示命令;1,表示数据;
void OLED_WR_Byte(u8 dat,u8 cmd)
{
    u8 i;
    if(cmd)
      OLED_DC_Set();
    else
      OLED_DC_Clr();
    OLED_CS_Clr();
    for(i=0;i<8;i++)
    {
        OLED_SCLK_Clr();
        if(dat&0x80)
           OLED_SDIN_Set();
        else
           OLED_SDIN_Clr();
        OLED_SCLK_Set();
        dat<<=1;
    }
    OLED_CS_Set();
    OLED_DC_Set();
}
void OLED_Set_Pos(unsigned char x, unsigned char y)
{
    OLED_WR_Byte(0xb0+y,OLED_CMD);
    OLED_WR_Byte((((x+2)&0xf0)>>4)|0x10,OLED_CMD);
    OLED_WR_Byte(((x+2)&0x0f),OLED_CMD);
}

6、接下来就是沁恒微电子科技汉子的显示驱动

//显示汉字
void OLED_ShowCHinese(u8 x,u8 y,u8 no)
{
    u8 t,adder=0;
    OLED_Set_Pos(x,y);
    for(t=0;t<16;t++)
        {
                OLED_WR_Byte(Hzk[2*no][t],OLED_DATA);
                adder+=1;
     }
        OLED_Set_Pos(x,y+1);
    for(t=0;t<16;t++)
            {
                OLED_WR_Byte(Hzk[2*no+1][t],OLED_DATA);
                adder+=1;
      }
}

字库的编写如下

char Hzk[][32]={
{0x10,0x60,0x02,0x8C,0x00,0x80,0x00,0xF0,0x02,0x04,0x18,0x00,0x00,0x80,0x00,0x00},
{0x04,0x04,0x7E,0x01,0x08,0x07,0x00,0x3F,0x40,0x40,0x40,0x40,0x78,0x00,0x07,0x00},/*"沁",0*/

{0x00,0xE0,0x00,0xFF,0x10,0x20,0x02,0xF2,0x92,0x92,0x92,0x92,0x92,0xF2,0x02,0x00},
{0x01,0x00,0x00,0xFF,0x00,0x00,0x40,0x4F,0x44,0x44,0x44,0x44,0x44,0x4F,0x40,0x00},/*"恒",1*/

{0x10,0x88,0xC4,0x33,0x80,0x9E,0x90,0x9F,0x90,0x9E,0x20,0xD8,0x17,0xF0,0x10,0x00},
{0x01,0x00,0xFF,0x80,0x40,0x3E,0x02,0x02,0x3E,0x10,0x88,0x67,0x18,0x67,0x80,0x00},/*"微",2*/

{0x00,0x00,0xF8,0x88,0x88,0x88,0x88,0xFF,0x88,0x88,0x88,0x88,0xF8,0x00,0x00,0x00},
{0x00,0x00,0x1F,0x08,0x08,0x08,0x08,0x7F,0x88,0x88,0x88,0x88,0x9F,0x80,0xF0,0x00},/*"电",3*/

{0x80,0x82,0x82,0x82,0x82,0x82,0x82,0xE2,0xA2,0x92,0x8A,0x86,0x82,0x80,0x80,0x00},
{0x00,0x00,0x00,0x00,0x00,0x40,0x80,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"子",4*/

{0x24,0x24,0xA4,0xFE,0xA3,0x22,0x00,0x22,0xCC,0x00,0x00,0xFF,0x00,0x00,0x00,0x00},
{0x08,0x06,0x01,0xFF,0x00,0x01,0x04,0x04,0x04,0x04,0x04,0xFF,0x02,0x02,0x02,0x00},/*"科",5*/

{0x10,0x10,0x10,0xFF,0x10,0x90,0x08,0x88,0x88,0x88,0xFF,0x88,0x88,0x88,0x08,0x00},
{0x04,0x44,0x82,0x7F,0x01,0x80,0x80,0x40,0x43,0x2C,0x10,0x28,0x46,0x81,0x80,0x00},/*"技",6*/

};

7、屏幕上边输出的72000000是获取的单片机工作的频率代码如下

//显示2个数字
//x,y :起点坐标
//len :数字的位数
//size:字体大小
//mode:模式   0,填充模式;1,叠加模式
//num:数值(0~4294967295);
void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size)
{
    u8 t,temp;
    u8 enshow=0;
    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+(size/2)*t,y,' ');
                continue;
            }else enshow=1;

        }
        OLED_ShowChar(x+(size/2)*t,y,temp+'0');
    }
}

8、完成以上这些应该就可以正常显示了,主函数直接调用就可以了,调用之前记得要初始化这些操作
 

int main(void)
{
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	Delay_Init();                   //延时函数初始化
	USART_Printf_Init(115200);      //串口初始化波特率115200
	LED_GPIO_Config();              //LED的IO口配置初始化
	OLED_Init();                    //液晶屏初始化
	printf("SystemClk:%d\r\n",SystemCoreClock);     //打印时钟频率
	printf("This is printf example\r\n");
	OLED_ShowNum(40,0,SystemCoreClock,8,16);//显示ASCII字符的码值
    OLED_ShowCHinese(0,3,0);//沁
    OLED_ShowCHinese(18,3,1);//恒
    OLED_ShowCHinese(36,3,2);//微
    OLED_ShowCHinese(54,3,3);//电
    OLED_ShowCHinese(72,3,4);//子
    OLED_ShowCHinese(90,3,5);//科
    OLED_ShowCHinese(108,3,6);//技
	while(1)
  {
	    LED_Blink(500);     //LED闪烁函数 500ms一次

  }
}

至此SPI驱动SSD1306液晶显示屏的工程已经完成了,@bigbat你的问题可以参考

赞赏

1

查看全部赞赏


回复

1447

帖子

2

资源

纯净的硅(高级)

谢谢,几天前@eew_VHNtMb,已经解决了。主要是

SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8;

这个参数修改后就可以了。2,4也可以。 


回复

1447

帖子

2

资源

纯净的硅(高级)

我使用的是硬件SPI不是模拟的,这样的测试和GPIO没有区别。我的目的不是使用OLED屏,而是要测试SPI功能。呵呵楼主理解错了。


回复

42

帖子

0

资源

一粒金砂(中级)

"6、接下来就是沁恒微电子科技汉子的显示驱动"

楼主是让我们找bug的,别误会了~


回复

771

帖子

2

资源

版主

感谢分享,期待后续的测评计划帖子哈,我也会持续关注你的哈!!!


回复
您需要登录后才可以回帖 登录 | 注册

最新文章 更多>>
    关闭
    站长推荐上一条 1/6 下一条

    About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

    站点相关: 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

    北京市海淀区知春路23号集成电路设计园量子银座1305 电话:(010)82350740 邮编:100191

    电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2021 EEWORLD.com.cn, Inc. All rights reserved
    快速回复 返回顶部 返回列表