返回列表 发新帖我要提问本帖赏金: 50.00元(功能说明)

[CW32F030系列] 【CW32F030CxTx StartKit测评】5.硬件SPI驱动OLED

[复制链接]
2882|16
 楼主| zhouminjie 发表于 2022-8-8 00:47 | 显示全部楼层 |阅读模式
此篇介绍使用硬件SPI1轮询模式来实现驱动OLED显示屏

硬件连接

GND ——  GND

VCC ——  3.3V

DO  ——  PA5
DI  ——  PA7
RES ——  PB1
DC  ——  PB0
CS  ——  PA4

软件代码

SPI1配置:

  1. //SPI初始化
  2. void SPI_Initial(void)
  3. {
  4.     SPI_InitTypeDef SPI_InitStructure;
  5.     GPIO_InitTypeDef GPIO_InitStructure;

  6.     /* Enable GPIO clock for SPI_MASTER */
  7.     RCC_AHBPeriphClk_Enable(SPI_MASTER_GPIO_CLK | RCC_SPI_CS, ENABLE);
  8.     /* Enable SPI_MASTER Periph clock */
  9.     RCC_APBPeriphClk_Enable2(SPI_MASTER_CLK, ENABLE);

  10.     //SPI SCK MOSI MISO 复用
  11.     SPI_AF_SCK;
  12.     SPI_AF_MISO;
  13.     SPI_AF_MOSI;

  14.     //GPIO_CS初始化设置
  15.     GPIO_InitStructure.Pins = PIN_SPI_CS;
  16.     GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
  17.     GPIO_InitStructure.IT = GPIO_IT_NONE;
  18.     GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
  19.     GPIO_Init(PORT_SPI_CS, &GPIO_InitStructure);
  20.     SPI_CS_DISABLE;
  21.     /* Configure SPI_MASTER pins: SCK and MOSI ---------------------------------*/
  22.     /* Configure SCK and MOSI pins as Alternate Function Push Pull */
  23.     GPIO_InitStructure.Pins = SPI_MASTER_PIN_SCK | SPI_MASTER_PIN_MOSI;
  24.     GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
  25.     GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
  26.     GPIO_Init(SPI_MASTER_GPIO, &GPIO_InitStructure);
  27.     /* Configure MISO pin as Input Floating  */
  28.     GPIO_InitStructure.Pins = SPI_MASTER_PIN_MISO;
  29.     GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
  30.     GPIO_Init(SPI_MASTER_GPIO, &GPIO_InitStructure);

  31.     /* SPI_MASTER configuration ------------------------------------------------*/
  32.     SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;    // 双线全双工
  33.     SPI_InitStructure.SPI_Mode = SPI_Mode_Master;                         // 主机模式
  34.     SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;                     // 帧数据长度为8bit
  35.     SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;                           // 时钟空闲电平为高
  36.     SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;                          // 第2个边沿采样
  37.     SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;                             // 片选信号由SSI寄存器控制
  38.     SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_128;  // 波特率为PCLK的128分频,16M/128=125000
  39.     SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;                    // 最高有效位 MSB 收发在前
  40.     SPI_InitStructure.SPI_Speed = SPI_Speed_Low;                          // 低速SPI
  41.     SPI_Init(SPI_MASTER, &SPI_InitStructure);

  42.     /* Enable SPI_MASTER */
  43.     SPI_Cmd(SPI_MASTER, ENABLE);

  44. }

OLED代码:

  1. //向设备写控制命令
  2. static void OLED_Write_CMD(unsigned char cmd)
  3. {
  4.     #ifdef HW_I2C
  5.     unsigned char tx_buf[BUF_SIZE] = {0x00, cmd};
  6.     I2C_MasterSendDataToSlave(CW_I2C2, tx_buf, BUF_SIZE);
  7.     #endif
  8.     #ifdef SW_I2C
  9.     I2C_Start();
  10.     I2C_Send_Byte(0x78);
  11.     I2C_Wait_Ack();
  12.     I2C_Send_Byte(0x00);
  13.     I2C_Wait_Ack();
  14.     I2C_Send_Byte(cmd);
  15.     I2C_Wait_Ack();
  16.     I2C_Stop();
  17.     #endif
  18.     #ifdef HW_SPI
  19.     OLED_CS_LOW;
  20.     OLED_DC_LOW;

  21.     while (SPI_GetFlagStatus(SPI_MASTER, SPI_FLAG_TXE) == RESET);

  22.     SPI_SendData(SPI_MASTER, cmd);

  23.     while (SPI_GetFlagStatus(SPI_MASTER, SPI_FLAG_RXNE) == RESET);

  24.     SPI_ReceiveData(SPI_MASTER);
  25.     OLED_CS_HIGH;
  26.     #endif
  27.     #ifdef SW_SPI
  28.     OLED_CS_LOW;
  29.     OLED_DC_LOW;
  30.     SPI_WriteByte(cmd);
  31.     OLED_CS_HIGH;
  32.     #endif
  33. }

  34. //向设备写数据
  35. static void OLED_Write_Date(unsigned char date)
  36. {
  37.     #ifdef HW_I2C
  38.     unsigned char tx_buf[BUF_SIZE] = {0x40, date};
  39.     I2C_MasterSendDataToSlave(CW_I2C2, tx_buf, BUF_SIZE);
  40.     #endif
  41.     #ifdef SW_I2C
  42.     I2C_Start();
  43.     I2C_Send_Byte(0x78);
  44.     I2C_Wait_Ack();
  45.     I2C_Send_Byte(0x40);
  46.     I2C_Wait_Ack();
  47.     I2C_Send_Byte(date);
  48.     I2C_Wait_Ack();
  49.     I2C_Stop();
  50.     #endif
  51.     #ifdef HW_SPI
  52.     OLED_CS_LOW;
  53.     OLED_DC_HIGH;

  54.     while (SPI_GetFlagStatus(SPI_MASTER, SPI_FLAG_TXE) == RESET);

  55.     SPI_SendData(SPI_MASTER, date);

  56.     while (SPI_GetFlagStatus(SPI_MASTER, SPI_FLAG_RXNE) == RESET);

  57.     SPI_ReceiveData(SPI_MASTER);
  58.     OLED_CS_HIGH;
  59.     #endif
  60.     #ifdef SW_SPI
  61.     OLED_CS_LOW;
  62.     OLED_DC_HIGH;
  63.     SPI_WriteByte(date);
  64.     OLED_CS_HIGH;
  65.     #endif
  66. }

  67. //坐标设置
  68. static void OLED_Set_Pos(unsigned char x, unsigned char y)
  69. {
  70.     OLED_Write_CMD(0xB0 + y);
  71.     OLED_Write_CMD(((x & 0xF0) >> 4) | 0x10);
  72.     OLED_Write_CMD(x & 0x0F);
  73. }

  74. //开启OLED显示
  75. static void OLED_Display_On(void)
  76. {
  77.     OLED_Write_CMD(0x8D); //SET DCDC命令
  78.     OLED_Write_CMD(0x14); //DCDC ON
  79.     OLED_Write_CMD(0xAF); //DISPLAY ON
  80. }

  81. //关闭OLED显示
  82. static void OLED_Display_Off(void)
  83. {
  84.     OLED_Write_CMD(0x8D); //SET DCDC命令
  85.     OLED_Write_CMD(0x10); //DCDC OFF
  86.     OLED_Write_CMD(0xAE); //DISPLAY OFF
  87. }

  88. //OLED清屏
  89. void OLED_Clear(void)
  90. {
  91.     unsigned char cnt, count;

  92.     for(cnt = 0; cnt < 8; cnt++)
  93.     {
  94.         OLED_Write_CMD(0xB0 + cnt);
  95.         OLED_Write_CMD(0x00);
  96.         OLED_Write_CMD(0x10);

  97.         for(count = 0; count < 128; count++)
  98.         {
  99.             OLED_Write_Date(0x00);
  100.         }
  101.     }
  102. }

  103. //OLED清行
  104. void OLED_Clear_Row(unsigned char n)
  105. {
  106.     unsigned char count;

  107.     OLED_Write_CMD(0xB0 + n);
  108.     OLED_Write_CMD(0x00);
  109.     OLED_Write_CMD(0x10);

  110.     for(count = 0; count < 128; count++)
  111.     {
  112.         OLED_Write_Date(0x00);
  113.     }
  114. }

  115. //OLED填满屏幕
  116. void OLED_Fill(void)
  117. {
  118.     unsigned char cnt, count;

  119.     for(cnt = 0; cnt < 8; cnt++)
  120.     {
  121.         OLED_Write_CMD(0xB0 + cnt); //设置页地址(0~7)
  122.         OLED_Write_CMD(0x00); //设置显示位置—列低地址
  123.         OLED_Write_CMD(0x10); //设置显示位置—列高地址

  124.         for(count = 0; count < 128; count++)
  125.         {
  126.             OLED_Write_Date(0x01);
  127.         }
  128.     }
  129. }

  130. //指定位置显示一个字符
  131. //x:0~127
  132. //y:0~63
  133. //chr:字符
  134. //mode:0,反白显示;1,正常显示
  135. //size:选择字体 16/12
  136. void OLED_ShowChar(unsigned char x, unsigned char y, unsigned char chr, unsigned char size)
  137. {
  138.     unsigned char offset = 0, cnt = 0;

  139.     offset = chr - ' '; //计算偏移量

  140.     if(x > 128 - 1)
  141.     {
  142.         x = 0;
  143.         y = y + 2;
  144.     }

  145.     if(size == 16)
  146.     {
  147.         OLED_Set_Pos(x, y);

  148.         for(cnt = 0; cnt < 8; cnt++)
  149.         {
  150.             OLED_Write_Date(F8x16[offset * 16 + cnt]);
  151.         }

  152.         OLED_Set_Pos(x, y + 1);

  153.         for(cnt = 0; cnt < 8; cnt++)
  154.         {
  155.             OLED_Write_Date(F8x16[offset * 16 + cnt + 8]);
  156.         }
  157.     }
  158.     else
  159.     {
  160.         OLED_Set_Pos(x, y);

  161.         for(cnt = 0; cnt < 6; cnt++)
  162.         {
  163.             OLED_Write_Date(F6x8[offset][cnt]);
  164.         }
  165.     }
  166. }

  167. unsigned int oled_pow(unsigned char m, unsigned char n)
  168. {
  169.     unsigned int result = 1;

  170.     while(n--)
  171.     {
  172.         result *= m;
  173.     }

  174.     return result;
  175. }

  176. //指定位置显示一个数字
  177. //x,y:起点坐标
  178. //num:数值(0~4294967295)
  179. //len:数字的位数
  180. //size:字体大小
  181. //mode:模式        0,填充模式;1,叠加模式
  182. void OLED_ShowNum(unsigned char x, unsigned char y, unsigned int num, unsigned char len, unsigned char size)
  183. {
  184.     unsigned char cnt, temp;
  185.     unsigned char show = 0;

  186.     for(cnt = 0; cnt < len; cnt++)
  187.     {
  188.         temp = (num / oled_pow(10, len - cnt - 1)) % 10;

  189.         if(show == 0 && cnt < (len - 1))
  190.         {
  191.             if(temp == 0)
  192.             {
  193.                 OLED_ShowChar(x + (size / 2) * cnt, y, ' ', size);
  194.                 continue;
  195.             }
  196.             else
  197.             {
  198.                 show = 1;
  199.             }
  200.         }

  201.         OLED_ShowChar(x + (size / 2) * cnt, y, temp + '0', size);
  202.     }
  203. }

  204. //指定位置显示字符串
  205. void OLED_ShowString(unsigned char x, unsigned char y, unsigned char *chr, unsigned char size)
  206. {
  207.     unsigned char cnt = 0;

  208.     while(chr[cnt] != '\0')
  209.     {
  210.         OLED_ShowChar(x, y, chr[cnt], size);
  211.         x += 8;

  212.         if(x > 120)
  213.         {
  214.             x = 0;
  215.             y += 2;
  216.         }

  217.         cnt++;
  218.     }
  219. }

  220. //显示汉字
  221. void OLED_ShowCHinese(unsigned char x, unsigned char y, unsigned char no)
  222. {
  223.     unsigned char cnt, addr = 0;

  224.     OLED_Set_Pos(x, y);

  225.     for(cnt = 0; cnt < 16; cnt++)
  226.     {
  227.         OLED_Write_Date(Hzk[2 * no][cnt]);
  228.         addr++;
  229.     }

  230.     OLED_Set_Pos(x, y + 1);

  231.     for(cnt = 0; cnt < 16; cnt++)
  232.     {
  233.         OLED_Write_Date(Hzk[2 * no + 1][cnt]);
  234.         addr++;
  235.     }
  236. }

  237. //显示图片
  238. /*
  239.         @brief                        显示图片
  240.         @param                        x0:起始列地址
  241.                                         y0:起始页地址
  242.                                         x1:终止列地址
  243.                                         y1:终止页地址
  244.                                         BMP[]:存放图片代码的数组
  245.         @retval                        无
  246. */
  247. void OLED_DrawBMP(unsigned char x0, unsigned char y0, unsigned char x1, unsigned char y1, unsigned char BMP[])
  248. {
  249.     unsigned int j = 0; //定义变量
  250.     unsigned char x, y; //定义变量

  251.     if(y1 % 8 == 0)
  252.     {
  253.         y = y1 / 8; //判断终止页是否为8的整数倍
  254.     }
  255.     else
  256.     {
  257.         y = y1 / 8 + 1;
  258.     }

  259.     for(y = y0; y < y1; y++) //从起始页开始,画到终止页
  260.     {
  261.         OLED_Set_Pos(x0, y); //在页的起始列开始画

  262.         for(x = x0; x < x1; x++) //画x1 - x0 列
  263.         {
  264.             OLED_Write_Date(BMP[j++]); //画图片的点
  265.         }
  266.     }
  267. }

  268. //显示动图
  269. /*
  270.         @brief                        显示动图
  271.         @param                        x0:起始列地址
  272.                                 y0:起始页地址
  273.                                 x1:终止列地址
  274.                                 y1:终止页地址
  275.                                 k: 帧个数
  276.                                 m: 单帧数组大小
  277.                                 BMP[][m]:存放动图代码的数组
  278.         @retval                        无
  279. */
  280. void OLED_DrawGIF(unsigned char x0, unsigned char y0, unsigned char x1, unsigned char y1, unsigned char k, int m, const unsigned char GIF[][m])
  281. {
  282.     unsigned int j = 0; //定义变量
  283.     unsigned char x, y, i; //定义变量

  284.     if(y1 % 8 == 0)
  285.     {
  286.         y = y1 / 8; //判断终止页是否为8的整数倍
  287.     }
  288.     else
  289.     {
  290.         y = y1 / 8 + 1;
  291.     }

  292.     for (i = 0; i < k; i++) //从第一帧开始画
  293.     {
  294.         j = 0;

  295.         for(y = y0; y < y1; y++) //从起始页开始,画到终止页
  296.         {
  297.             OLED_Set_Pos(x0, y); //在页的起始列开始画

  298.             for(x = x0; x < x1; x++) //画x1 - x0 列
  299.             {
  300.                 OLED_Write_Date(GIF[i][j++]); //画图片的点
  301.             }
  302.         }

  303.         //Delay_Ms(80);
  304.     }
  305. }


  306. #if defined SW_SPI || defined HW_SPI
  307. //SPI驱动方式DC、RES引脚初始化
  308. void OLED_SPI_GPIO_Init(void)
  309. {
  310.     GPIO_InitTypeDef GPIO_InitStructure;

  311.     //根据GPIO组初始化GPIO时钟
  312.     RCC_AHBPeriphClk_Enable( RCC_OLED_DC | RCC_OLED_RES, ENABLE);
  313.     //GPIO_DC初始化设置
  314.     GPIO_InitStructure.Pins = PIN_OLED_DC;
  315.     GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
  316.     GPIO_InitStructure.IT = GPIO_IT_NONE;
  317.     GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
  318.     GPIO_Init(PORT_OLED_DC, &GPIO_InitStructure);
  319.     //GPIO_RES初始化设置
  320.     GPIO_InitStructure.Pins = PIN_OLED_RES;
  321.     GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
  322.     GPIO_InitStructure.IT = GPIO_IT_NONE;
  323.     GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
  324.     GPIO_Init(PORT_OLED_RES, &GPIO_InitStructure);

  325.     OLED_RES_LOW;
  326.     Delay_Ms(200);
  327.     OLED_RES_HIGH;
  328. }
  329. #endif


  330. //OLED初始化
  331. void OLED_Init(void)
  332. {
  333.     #ifdef SW_I2C
  334.     I2C_Init();
  335.     #endif
  336.     #ifdef HW_I2C
  337.     I2C_Init();
  338.     #endif
  339.     #ifdef SW_SPI
  340.     SPI_Initial();
  341.     OLED_SPI_GPIO_Init();
  342.     #endif
  343.     #ifdef HW_SPI
  344.     SPI_Initial();
  345.     OLED_SPI_GPIO_Init();
  346.     #endif
  347.     Delay_Ms(200);
  348.     OLED_Write_CMD(0xAE); //display off
  349.     OLED_Write_CMD(0x00); //set low column address
  350.     OLED_Write_CMD(0x10); //set high column address
  351.     OLED_Write_CMD(0x40); //set start line address
  352.     OLED_Write_CMD(0xB0); //set page address
  353.     OLED_Write_CMD(0x81); //contract control
  354.     OLED_Write_CMD(0xFF); //128
  355.     OLED_Write_CMD(0xA1); //set segment remap
  356.     OLED_Write_CMD(0xA6); //normal / reverse
  357.     OLED_Write_CMD(0xA8); //set multiplex ratio(1 to 64)
  358.     OLED_Write_CMD(0x3F); //1/32 duty
  359.     OLED_Write_CMD(0xC8); //Com scan direction
  360.     OLED_Write_CMD(0xD3); //set display offset
  361.     OLED_Write_CMD(0x00); //
  362.     OLED_Write_CMD(0xD5); //set osc division
  363.     OLED_Write_CMD(0x80); //
  364.     OLED_Write_CMD(0xD8); //set area color mode off
  365.     OLED_Write_CMD(0x05); //
  366.     OLED_Write_CMD(0xD9); //Set Pre-Charge Period
  367.     OLED_Write_CMD(0xF1); //
  368.     OLED_Write_CMD(0xDA); //set com pin configuartion
  369.     OLED_Write_CMD(0x12); //
  370.     OLED_Write_CMD(0xDB); //set Vcomh
  371.     OLED_Write_CMD(0x30); //
  372.     OLED_Write_CMD(0x8D); //set charge pump enable
  373.     OLED_Write_CMD(0x14); //
  374.     OLED_Write_CMD(0xAF); //turn on oled panel
  375. }

运行测试

WeChat_20220807224832_ (1).gif

测试代码

CW32F030CxTx_HW_SPI_OLED.zip (261.26 KB, 下载次数: 12)





打赏榜单

21ic小管家 打赏了 50.00 元 2022-08-10
理由:贡献奖

weifeng90 发表于 2022-8-8 08:43 来自手机 | 显示全部楼层
GIF动图显示不完整
 楼主| zhouminjie 发表于 2022-8-8 16:37 | 显示全部楼层
拍视频时候没有拍完整
quickman 发表于 2022-9-5 16:04 | 显示全部楼层
可以使用dma驱动吗
quickman 发表于 2022-9-8 08:16 | 显示全部楼层
硬件SPI直接驱动不?   
robertesth 发表于 2022-9-8 08:41 | 显示全部楼层
单片机驱动oled简单吗
fengm 发表于 2022-9-8 09:54 | 显示全部楼层
求SPI接法                     
hearstnorman323 发表于 2022-9-8 11:07 | 显示全部楼层
怎么提高刷屏速度                     
macpherson 发表于 2022-9-8 12:59 | 显示全部楼层
驱动oled 不管是SPI还是IIC为啥都是模拟的
qiufengsd 发表于 2022-9-8 14:10 | 显示全部楼层
驱动的OLED屏?
pentruman 发表于 2022-9-8 16:53 | 显示全部楼层
spi总线驱动是不是很流畅?
chenci2013 发表于 2022-9-10 19:16 | 显示全部楼层
SPI接口要写中断吗
isseed 发表于 2022-9-10 20:16 | 显示全部楼层
SPI驱动怎么用?         
louliana 发表于 2022-9-10 21:21 | 显示全部楼层
oled spi方式 DC线接哪里
fengm 发表于 2022-9-11 12:23 | 显示全部楼层
ssd1306d的例程吗?
wangdezhi 发表于 2022-10-1 14:18 | 显示全部楼层
SPI驱动OLED              
Bowclad 发表于 2022-10-4 18:59 | 显示全部楼层
求spi接法
您需要登录后才可以回帖 登录 | 注册

本版积分规则

33

主题

140

帖子

3

粉丝
快速回复 在线客服 返回列表 返回顶部