[PIC®/AVR®/dsPIC®产品] [PIC18F57Q43Curiosity Nano] 3.软件模拟SPI驱动OLED

[复制链接]
25460|15
 楼主| zhouminjie 发表于 2022-8-22 23:19 | 显示全部楼层 |阅读模式
本帖最后由 zhouminjie 于 2022-8-22 23:21 编辑

本片介绍在PIC18F57Q43上实现软件模拟SPI驱动0.96OLED
新建工程,打开MCC配置
配置系统时钟频率:时钟源选择HFINTOSC,时钟频率选择64MHz,分频设置选择不分频,得到系统时钟频率为64MHz

配置引脚:在Package View中设置RA3——DC、RA4——CS、RB1——MISO、RB2——MOSI、RB3——SCK、RD4——RES


添加DELAY Foundation services

点击Generate生成配置代码

新建.c(.h)文件,添加sw_spi代码
  1. #include"sw_spi.h"

  2. //SPI初始化
  3. void SPI_Initial(void)
  4. {
  5.     SPI_CS_DISABLE;
  6.     SPI_SCK_HIGH;
  7.     SPI_MOSI_HIGH;
  8. }

  9. //SPI写一字节数据,TxData --- 发送的字节数据
  10. void SPI_WriteByte(unsigned char TxData)
  11. {
  12.     unsigned char cnt;

  13.     for(cnt = 0; cnt < 8; cnt++)
  14.     {
  15.         SPI_SCK_LOW;                                 //时钟 - 低
  16.         Delay_Us(1);

  17.         if(TxData & 0x80)                            //发送数据
  18.             SPI_MOSI_HIGH;
  19.         else
  20.             SPI_MOSI_LOW;

  21.         TxData <<= 1;

  22.         Delay_Us(1);
  23.         SPI_SCK_HIGH;                                //时钟 - 高
  24.         Delay_Us(1);
  25.     }
  26. }

  27. //SPI读一字节数据,读回来的字节数据
  28. unsigned char SPI_ReadByte(void)
  29. {
  30.     unsigned char cnt;
  31.     unsigned char RxData = 0;

  32.     for(cnt = 0; cnt < 8; cnt++)
  33.     {
  34.         SPI_SCK_LOW;                                 //时钟 - 低
  35.         Delay_Us(1);

  36.         RxData <<= 1;

  37.         if(SPI_MISO_READ)                            //读取数据
  38.         {
  39.             RxData |= 0x01;
  40.         }

  41.         SPI_SCK_HIGH;                                //时钟 - 高
  42.         Delay_Us(1);
  43.     }

  44.     return RxData;
  45. }


新建.c(.h)文件,添加oled代码
  1. #include"oled.h"

  2. //向设备写控制命令
  3. static void OLED_Write_CMD(unsigned char cmd)
  4. {
  5.     OLED_CS_LOW;
  6.     OLED_DC_LOW;
  7.     SPI_WriteByte(cmd);
  8.     OLED_CS_HIGH;
  9. }

  10. //向设备写数据
  11. static void OLED_Write_Data(unsigned char data)
  12. {
  13.     OLED_CS_LOW;
  14.     OLED_DC_HIGH;
  15.     SPI_WriteByte(data);
  16.     OLED_CS_HIGH;
  17. }

  18. //坐标设置
  19. static void OLED_Set_Pos(unsigned char x, unsigned char y)
  20. {
  21.     OLED_Write_CMD(0xB0 + y);
  22.     OLED_Write_CMD(((x & 0xF0) >> 4) | 0x10);
  23.     OLED_Write_CMD(x & 0x0F);
  24. }

  25. //开启OLED显示
  26. static void OLED_Display_On(void)
  27. {
  28.     OLED_Write_CMD(0x8D); //SET DCDC命令
  29.     OLED_Write_CMD(0x14); //DCDC ON
  30.     OLED_Write_CMD(0xAF); //DISPLAY ON
  31. }

  32. //关闭OLED显示
  33. static void OLED_Display_Off(void)
  34. {
  35.     OLED_Write_CMD(0x8D); //SET DCDC命令
  36.     OLED_Write_CMD(0x10); //DCDC OFF
  37.     OLED_Write_CMD(0xAE); //DISPLAY OFF
  38. }

  39. //OLED清屏
  40. void OLED_Clear(void)
  41. {
  42.     unsigned char cnt, count;

  43.     for(cnt = 0; cnt < 8; cnt++)
  44.     {
  45.         OLED_Write_CMD(0xB0 + cnt);
  46.         OLED_Write_CMD(0x00);
  47.         OLED_Write_CMD(0x10);

  48.         for(count = 0; count < 128; count++)
  49.         {
  50.             OLED_Write_Data(0x00);
  51.         }
  52.     }
  53. }

  54. //OLED清行
  55. void OLED_Clear_Row(unsigned char n)
  56. {
  57.     unsigned char count;

  58.     OLED_Write_CMD(0xB0 + n);
  59.     OLED_Write_CMD(0x00);
  60.     OLED_Write_CMD(0x10);

  61.     for(count = 0; count < 128; count++)
  62.     {
  63.         OLED_Write_Data(0x00);
  64.     }
  65. }

  66. //OLED填满屏幕
  67. void OLED_Fill(void)
  68. {
  69.     unsigned char cnt, count;

  70.     for(cnt = 0; cnt < 8; cnt++)
  71.     {
  72.         OLED_Write_CMD(0xB0 + cnt); //设置页地址(0~7)
  73.         OLED_Write_CMD(0x00); //设置显示位置—列低地址
  74.         OLED_Write_CMD(0x10); //设置显示位置—列高地址

  75.         for(count = 0; count < 128; count++)
  76.         {
  77.             OLED_Write_Data(0x01);
  78.         }
  79.     }
  80. }

  81. //指定位置显示一个字符
  82. //x:0~127
  83. //y:0~63
  84. //chr:字符
  85. //mode:0,反白显示;1,正常显示
  86. //size:选择字体 16/12
  87. void OLED_ShowChar(unsigned char x, unsigned char y, unsigned char chr, unsigned char size)
  88. {
  89.     unsigned char offset = 0, cnt = 0;

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

  91.     if(x > 128 - 1)
  92.     {
  93.         x = 0;
  94.         y = y + 2;
  95.     }

  96.     if(size == 16)
  97.     {
  98.         OLED_Set_Pos(x, y);

  99.         for(cnt = 0; cnt < 8; cnt++)
  100.         {
  101.             OLED_Write_Data(F8x16[offset * 16 + cnt]);
  102.         }

  103.         OLED_Set_Pos(x, y + 1);

  104.         for(cnt = 0; cnt < 8; cnt++)
  105.         {
  106.             OLED_Write_Data(F8x16[offset * 16 + cnt + 8]);
  107.         }
  108.     }
  109.     else
  110.     {
  111.         OLED_Set_Pos(x, y);

  112.         for(cnt = 0; cnt < 6; cnt++)
  113.         {
  114.             OLED_Write_Data(F6x8[offset][cnt]);
  115.         }
  116.     }
  117. }

  118. unsigned int oled_pow(unsigned char m, unsigned char n)
  119. {
  120.     unsigned int result = 1;

  121.     while(n--)
  122.     {
  123.         result *= m;
  124.     }

  125.     return result;
  126. }

  127. //指定位置显示一个数字
  128. //x,y:起点坐标
  129. //num:数值(0~4294967295)
  130. //len:数字的位数
  131. //size:字体大小
  132. //mode:模式        0,填充模式;1,叠加模式
  133. void OLED_ShowNum(unsigned char x, unsigned char y, unsigned int num, unsigned char len, unsigned char size)
  134. {
  135.     unsigned char cnt, temp;
  136.     unsigned char show = 0;

  137.     for(cnt = 0; cnt < len; cnt++)
  138.     {
  139.         temp = (num / oled_pow(10, len - cnt - 1)) % 10;

  140.         if(show == 0 && cnt < (len - 1))
  141.         {
  142.             if(temp == 0)
  143.             {
  144.                 OLED_ShowChar(x + (size / 2) * cnt, y, ' ', size);
  145.                 continue;
  146.             }
  147.             else
  148.             {
  149.                 show = 1;
  150.             }
  151.         }

  152.         OLED_ShowChar(x + (size / 2) * cnt, y, temp + '0', size);
  153.     }
  154. }

  155. //指定位置显示字符串
  156. void OLED_ShowString(unsigned char x, unsigned char y, unsigned char *chr, unsigned char size)
  157. {
  158.     unsigned char cnt = 0;

  159.     while(chr[cnt] != '\0')
  160.     {
  161.         OLED_ShowChar(x, y, chr[cnt], size);
  162.         x += 8;

  163.         if(x > 120)
  164.         {
  165.             x = 0;
  166.             y += 2;
  167.         }

  168.         cnt++;
  169.     }
  170. }

  171. //显示汉字
  172. void OLED_ShowCHinese(unsigned char x, unsigned char y, unsigned char no)
  173. {
  174.     unsigned char cnt, addr = 0;

  175.     OLED_Set_Pos(x, y);

  176.     for(cnt = 0; cnt < 16; cnt++)
  177.     {
  178.         OLED_Write_Data(Hzk[2 * no][cnt]);
  179.         addr++;
  180.     }

  181.     OLED_Set_Pos(x, y + 1);

  182.     for(cnt = 0; cnt < 16; cnt++)
  183.     {
  184.         OLED_Write_Data(Hzk[2 * no + 1][cnt]);
  185.         addr++;
  186.     }
  187. }

  188. //显示图片
  189. /*
  190.         [url=home.php?mod=space&uid=247401]@brief[/url]                        显示图片
  191.         @param                        x0:起始列地址
  192.                                         y0:起始页地址
  193.                                         x1:终止列地址
  194.                                         y1:终止页地址
  195.                                         BMP[]:存放图片代码的数组
  196.         @retval                        无
  197. */
  198. void OLED_DrawBMP(unsigned char x0, unsigned char y0, unsigned char x1, unsigned char y1, const unsigned char BMP[])
  199. {
  200.     unsigned int j = 0; //定义变量
  201.     unsigned char x, y; //定义变量

  202.     if(y1 % 8 == 0)
  203.     {
  204.         y = y1 / 8; //判断终止页是否为8的整数倍
  205.     }
  206.     else
  207.     {
  208.         y = y1 / 8 + 1;
  209.     }

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

  213.         for(x = x0; x < x1; x++) //画x1 - x0 列
  214.         {
  215.             OLED_Write_Data(BMP[j++]); //画图片的点
  216.         }
  217.     }
  218. }

  219. //显示动图
  220. /*
  221.         [url=home.php?mod=space&uid=247401]@brief[/url]                        显示动图
  222.         @param                        x0:起始列地址
  223.                                 y0:起始页地址
  224.                                 x1:终止列地址
  225.                                 y1:终止页地址
  226.                                 k: 帧个数
  227.                                 m: 单帧数组大小
  228.                                 BMP[][m]:存放动图代码的数组
  229.         @retval                        无
  230. */
  231. void OLED_DrawGIF(unsigned char x0, unsigned char y0, unsigned char x1, unsigned char y1, unsigned char k, int m, const unsigned char GIF[29][1024])
  232. {
  233.     unsigned int j = 0; //定义变量
  234.     unsigned char x, y, i; //定义变量
  235.     //unsigned int (*p)[m] = GIF;

  236.     if(y1 % 8 == 0)
  237.     {
  238.         y = y1 / 8; //判断终止页是否为8的整数倍
  239.     }
  240.     else
  241.     {
  242.         y = y1 / 8 + 1;
  243.     }

  244.     for (i = 0; i < k; i++) //从第一帧开始画
  245.     {
  246.         j = 0;

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

  250.             for(x = x0; x < x1; x++) //画x1 - x0 列
  251.             {
  252.                 OLED_Write_Data(GIF[i][j++]); //画图片的点//GIF[i][j++]
  253.             }
  254.         }

  255.         //Delay_Ms(80);
  256.     }
  257. }

  258. //SPI驱动方式DC、RES引脚初始化
  259. void OLED_SPI_GPIO_Init(void)
  260. {
  261.     OLED_RES_LOW;
  262.     DELAY_milliseconds(200);
  263.     OLED_RES_HIGH;   
  264. }
  265.    
  266. //OLED初始化
  267. void OLED_Init(void)
  268. {
  269.     SPI_Initial();
  270.     OLED_SPI_GPIO_Init();
  271.    
  272.     DELAY_milliseconds(200);
  273.     OLED_Write_CMD(0xAE); //display off
  274.     OLED_Write_CMD(0x00); //set low column address
  275.     OLED_Write_CMD(0x10); //set high column address
  276.     OLED_Write_CMD(0x40); //set start line address
  277.     OLED_Write_CMD(0xB0); //set page address
  278.     OLED_Write_CMD(0x81); //contract control
  279.     OLED_Write_CMD(0xFF); //128
  280.     OLED_Write_CMD(0xA1); //set segment remap
  281.     OLED_Write_CMD(0xA6); //normal / reverse
  282.     OLED_Write_CMD(0xA8); //set multiplex ratio(1 to 64)
  283.     OLED_Write_CMD(0x3F); //1/32 duty
  284.     OLED_Write_CMD(0xC8); //Com scan direction
  285.     OLED_Write_CMD(0xD3); //set display offset
  286.     OLED_Write_CMD(0x00); //
  287.     OLED_Write_CMD(0xD5); //set osc division
  288.     OLED_Write_CMD(0x80); //
  289.     OLED_Write_CMD(0xD8); //set area color mode off
  290.     OLED_Write_CMD(0x05); //
  291.     OLED_Write_CMD(0xD9); //Set Pre-Charge Period
  292.     OLED_Write_CMD(0xF1); //
  293.     OLED_Write_CMD(0xDA); //set com pin configuartion
  294.     OLED_Write_CMD(0x12); //
  295.     OLED_Write_CMD(0xDB); //set Vcomh
  296.     OLED_Write_CMD(0x30); //
  297.     OLED_Write_CMD(0x8D); //set charge pump enable
  298.     OLED_Write_CMD(0x14); //
  299.     OLED_Write_CMD(0xAF); //turn on oled panel
  300. }


编译调试
测试效果如下

测试工程




本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×
bestwell 发表于 2022-9-3 16:40 | 显示全部楼层
用I/O口使用软件模拟SPI通信怎么模拟
fentianyou 发表于 2022-9-3 18:34 | 显示全部楼层
怎么用spi接口控制12864屏
wilhelmina2 发表于 2022-9-3 18:54 | 显示全部楼层
6和7脚OLED的SPI驱动程序一样吗  
tifmill 发表于 2022-9-3 19:26 | 显示全部楼层
单片机驱动oled简单吗
cashrwood 发表于 2022-9-3 20:39 | 显示全部楼层
可以运行spi接口的ssd1306d的例程吗?
pklong 发表于 2022-9-4 22:07 | 显示全部楼层
SPI驱动OLED 12864   
vivilyly 发表于 2022-9-5 12:57 | 显示全部楼层
可以通过模拟spi来驱动吗  
mickit 发表于 2022-9-5 14:56 | 显示全部楼层
怎么提高刷屏速度  
averyleigh 发表于 2022-9-5 16:06 | 显示全部楼层
LED和OLED有什么区别?
tpgf 发表于 2022-9-7 14:19 | 显示全部楼层
模拟的几线制的spi啊
nawu 发表于 2022-9-7 14:34 | 显示全部楼层
mickit 发表于 2022-9-5 14:56
怎么提高刷屏速度

刷屏速度太快了也不好啊
aoyi 发表于 2022-9-7 14:42 | 显示全部楼层
cashrwood 发表于 2022-9-3 20:39
可以运行spi接口的ssd1306d的例程吗?

这种接口的屏其数据接收量是有限制的吧
zljiu 发表于 2022-9-7 14:49 | 显示全部楼层
bestwell 发表于 2022-9-3 16:40
用I/O口使用软件模拟SPI通信怎么模拟

模拟其通讯的时序呀
gwsan 发表于 2022-9-7 14:57 | 显示全部楼层
模拟spi比模拟iic难一点
tfqi 发表于 2022-9-7 15:05 | 显示全部楼层
一帧一帧的刷新是手机录制导致的吗
您需要登录后才可以回帖 登录 | 注册

本版积分规则

33

主题

140

帖子

3

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