M61 gpio模拟i2c 点亮0.96寸屏幕

[复制链接]
查看2294 | 回复20 | 2023-11-27 21:30:33 | 显示全部楼层 |阅读模式

说在前面
本教程适合没什么硬件基础的人,因为我本身也没基础,纯靠几天百度。
i2c协议本身足够简单,所以这里使用gpio模拟i2c协议即可。
如果觉得啰嗦,或者已有一定基础,可以直接跳到代码部分。
本着先做出来再做好,先看到效果再来优化的想法。
1.jpg



一、基础知识
1、了解 i2c是通过scl和sda的高低电平来传输数据。
2、知道发送一条完整信息的格式如下图

ns_attach_image_13121701070914802.png

3、要点亮的屏幕(比如4pin-LCM(新款cirssd1315))的手册,需要时查看手册即可


二、思路

查看手册的点亮步骤,我们的4pin屏幕可以不用管res,所以就从Set Display Off开始。
先发送0xAE,再发送0xD5,...
拆解这个过程,全都是发送一些数据给屏幕,所以首先要实现发送一条数据的代码。
拆解发送一条数据的过程,知道是先发送开始,设备地址,读写位,一直到停止位,而怎么发送,i2c协议已经告诉我们了。
思路清晰,那么就可以开始写代码了。


三、代码
  1. <blockquote>/**
复制代码



本帖被以下淘专辑推荐:

回复

使用道具 举报

lclight | 2023-11-27 21:32:22 | 显示全部楼层
本帖最后由 lclight 于 2023-11-27 21:33 编辑
  1. /**
  2. * @file main.c
  3. * @author lclight
  4. * @brief
  5. * @version 0.1
  6. * @date 2023-11-26
  7. *
  8. * @copyright Copyright (c) 2023
  9. *
  10. */
  11. // 头文件,为省事直接写了一大堆
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #include <FreeRTOS.h>
  16. #include <task.h>
  17. #include <time.h>
  18. #include <unistd.h>
  19. #include "board.h"
  20. #include "log.h"
  21. #include "bflb_mtimer.h"
  22. #include "bflb_i2c.h"
  23. #include "bflb_gpio.h"
  24. #include "bflb_audac.h"
  25. #include "bflb_dma.h"
  26. #include "bl616_glb.h"
  27. #include "bflb_flash.h"
  28. #include <queue.h>
  29. #include <semphr.h>
  30. #include <timers.h>

  31. // 选择支持i2c的两个针脚,接线也要按这个来接
  32. #define SDA GPIO_PIN_31
  33. #define SCL GPIO_PIN_30

  34. // sleep函数,封装一层,方便修改
  35. // 因为精度不够,这里用1太耗时,改为0比较合适,用usleep同样不行
  36. #define waittime(t) vTaskDelay(0)

  37. struct bflb_device_s *gpio;

  38. // 从机地址,从手册或者卖家给的例子中获得,如果没有,甚至可以用for从0~127逐个初始化再确定是哪个
  39. uint8_t addr = 0x78;

  40. // 显示的图片字模,本应该放在头文件的,可以自己修改,宽×高(像素): 128×64
  41. const uint8_t  *point;
  42. const uint8_t  picture_tab[]={
  43. 0x1,0x2,0x4,0x8,0xF0,0xA0,0x0,0x10,0x10,0x10,0x8,0x8,0x8,0x18,0x10,0x11,
  44. 0x1A,0xC,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,
  45. 0x2,0xFF,0x81,0x0,0x1C,0x30,0xED,0x87,0xC3,0x1,0x0,0x40,0xE0,0x80,0x0,0x0,
  46. 0x0,0x0,0x0,0x0,0x1,0x2,0x4,0xE4,0x33,0x38,0x2E,0xE9,0xC8,0xD8,0x90,0x20,
  47. 0x20,0x40,0xC0,0x80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1F,0x60,
  48. 0x80,0x0,0x0,0x80,0xC8,0x7C,0x4,0x3,0x0,0x0,0x80,0x80,0xC0,0x40,0x40,0x20,
  49. 0x20,0x20,0x20,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x20,0x60,0x60,0x60,0xE0,0xC0,
  50. 0xC0,0xC0,0x80,0x0,0x0,0x0,0x0,0x1,0x3,0x4,0x8,0x8,0x5,0x1,0x0,0x0,
  51. 0x6,0x4,0x8,0x10,0x20,0x40,0x80,0x1,0x3,0x7,0xD9,0x1A,0x6,0x6,0x4,0x0,
  52. 0x4,0x8,0x88,0xC8,0xC8,0xA0,0xA0,0xB0,0x10,0x10,0x10,0x10,0x10,0x10,0x90,0x90,
  53. 0x9C,0xB7,0x60,0x43,0x42,0xA6,0xB9,0x70,0xC0,0x40,0x81,0x81,0x1,0x0,0x0,0x0,
  54. 0x0,0x0,0x80,0x80,0x40,0x20,0x20,0xCF,0x39,0xE9,0x28,0x98,0xD8,0x58,0x58,0x59,
  55. 0x7E,0x74,0x7C,0x78,0x31,0x31,0xB1,0xB2,0xB2,0x72,0x36,0x14,0x94,0x94,0x94,0x94,
  56. 0x94,0x10,0x18,0x18,0x18,0x18,0x1C,0x1E,0x1A,0x19,0x11,0x10,0x10,0x10,0x10,0x10,
  57. 0x10,0x10,0x30,0x20,0x20,0x10,0x50,0x50,0xB0,0xA0,0x20,0x20,0x40,0x40,0xC0,0x80,
  58. 0x81,0x1,0x1,0x3,0x7,0x6,0xE,0x14,0x2C,0x58,0xB0,0x60,0xC0,0x80,0x0,0x0,
  59. 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xFE,0xE6,0x20,0x0,0x0,0x80,0xF0,0xDC,
  60. 0xEE,0xF5,0x35,0x10,0x18,0x18,0x10,0x14,0x14,0x18,0x38,0x30,0x60,0xE0,0xC0,0xC0,
  61. 0x1E,0x81,0x70,0xFE,0x0,0x0,0xFE,0x70,0xC0,0x7,0x1B,0xE3,0x85,0x89,0x91,0x91,
  62. 0xB1,0xF9,0x70,0x58,0xE8,0x78,0x68,0xD7,0x4C,0x7,0xE0,0x63,0x23,0x23,0xFB,0x3B,
  63. 0xB,0x19,0x1C,0x17,0x17,0x11,0x11,0x11,0x18,0x78,0x98,0x3B,0x3B,0x8C,0xEC,0x2C,
  64. 0x24,0x14,0x1E,0x1E,0xE,0x8C,0xC4,0xE4,0xE4,0xFC,0xF8,0x7C,0x7C,0xFA,0xF2,0xC2,
  65. 0x6,0xE,0x36,0xD6,0xD2,0xD2,0xF2,0xF2,0xC2,0xD3,0xC3,0x82,0x86,0x4,0x8,0x11,
  66. 0x61,0xC3,0x7,0xA,0x10,0x60,0x80,0x0,0x0,0x0,0x0,0x1,0x2,0xD,0x12,0x6C,
  67. 0x10,0x10,0x10,0x30,0x30,0x20,0x20,0x7F,0xC6,0x5,0xC4,0x4A,0x65,0x65,0xAF,0x3F,
  68. 0x79,0x78,0x70,0x70,0x60,0x60,0x60,0x30,0x0,0x20,0x20,0x20,0x0,0x0,0x21,0x21,
  69. 0x23,0x2,0x6,0x6,0x27,0x2C,0x28,0x22,0x40,0x43,0x46,0xC8,0x2B,0x20,0x0,0x10,
  70. 0x30,0x6C,0xC2,0xE1,0x30,0x8C,0xC6,0xB1,0xC,0x42,0x61,0x38,0x26,0x1,0x10,0x10,
  71. 0x10,0x8,0x8,0x8,0xC,0x4,0x4,0xC,0xC,0xCC,0xE9,0x33,0xF,0x1,0x0,0x0,
  72. 0x0,0x0,0x0,0x0,0x0,0x0,0xC,0xF,0x1F,0x1F,0x1F,0x8,0x3C,0x1F,0xF,0x3,
  73. 0x1F,0x0,0x0,0x1,0x3F,0xF0,0x90,0x90,0x90,0xD0,0xD0,0xD0,0xD0,0x90,0x80,0x80,
  74. 0x0,0x0,0x3,0x1C,0xF0,0x0,0x1,0xE,0xF0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  75. 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3,0x1E,0xE1,0x6,0x1C,0x30,0xC1,0x6,
  76. 0x18,0x61,0x6,0x18,0x60,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80,0x80,
  77. 0x80,0x80,0x80,0x80,0x40,0x40,0x40,0x20,0x20,0x10,0x10,0x18,0x17,0x10,0x20,0x20,
  78. 0x20,0xF0,0x1F,0x3B,0xE5,0x44,0x58,0xE8,0x8,0x30,0x70,0xA0,0x20,0x0,0x40,0x80,
  79. 0x80,0x80,0x0,0x0,0x0,0x0,0x0,0x0,0x3F,0xFF,0xC1,0x0,0x0,0x0,0x0,0x1C,
  80. 0x32,0x22,0x23,0x3F,0x0,0x4,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  81. 0x0,0x0,0x0,0x0,0x80,0xFF,0xC,0xC,0xC,0xC,0xC,0xC,0x4,0x4,0x4,0x0,
  82. 0x0,0x0,0x0,0x0,0x18,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  83. 0x20,0x20,0xA0,0xA0,0x10,0x50,0x70,0x30,0x20,0x18,0x18,0x1F,0xF0,0x0,0x0,0x3,
  84. 0x6,0xA,0xB,0xA,0xA,0x7,0x4,0x4,0x3,0x3,0x3,0x3,0x1,0x1,0x1,0x1,
  85. 0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80,0x80,0x40,0x40,0x40,0x40,0x60,0x20,
  86. 0x20,0x10,0xF,0x86,0x40,0x20,0x30,0x7F,0xC3,0x6,0x18,0x61,0x86,0x18,0x60,0x80,
  87. 0x0,0x0,0x1,0x1,0x0,0x2,0x2,0x2,0xC6,0x66,0x13,0x4F,0x58,0x60,0x80,0x0,
  88. 0x0,0x0,0x0,0x0,0x0,0x0,0xF8,0xFC,0xFC,0xFC,0xFC,0x8C,0x8F,0xFE,0xFC,0x70,
  89. 0x1E,0x0,0x0,0xC0,0xFF,0x87,0x87,0x87,0x86,0x86,0x86,0x86,0x0,0x0,0x0,0x0,
  90. 0x0,0x80,0x60,0x1C,0x7,0x0,0x40,0x38,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  91. 0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80,0xC0,0x7F,0x80,0x80,
  92. 0x80,0x80,0x80,0x0,0x0,0x0,0x80,0xC0,0x60,0x10,0x8,0x8,0x0,0x80,0xC0,0x60,
  93. 0xB0,0x38,0xD8,0x78,0x3C,0x16,0x6,0x1,0x0,0x80,0x0,0x0,0x0,0x0,0x0,0x0,
  94. 0x0,0x0,0x3,0x4,0x8,0x8,0x8,0x10,0x10,0x13,0x14,0x18,0x11,0x12,0x3C,0x30,
  95. 0x23,0x24,0x58,0x60,0xF0,0xD8,0x56,0x83,0xA1,0xB9,0xF9,0xF9,0xF8,0xB9,0xF8,0x59,
  96. 0x4B,0x4E,0x5E,0xF4,0xF8,0xF8,0xF8,0x30,0x21,0x7,0x7,0x17,0x7,0x3,0x1,0x10,
  97. 0x18,0x1C,0x13,0xB,0xF,0xD,0xD,0x8D,0x8D,0x49,0x49,0x21,0x90,0x98,0xCC,0x44,
  98. 0x63,0x71,0x18,0x2C,0x36,0x11,0x8,0x4,0x2,0x0,0x0,0x80,0xC0,0xF0,0x78,0x1E,
  99. 0x0,0x0,0x80,0x40,0x20,0x30,0x10,0x8,0x84,0xC2,0xA3,0x99,0x8C,0x3,0x7,0xD,
  100. 0x5,0x4,0x0,0xFE,0x2,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xF,0x38,0xD8,
  101. 0xA1,0x44,0x91,0x2C,0x5C,0xB8,0x40,0x80,0x0,0x0,0x1,0x1,0x2,0xC,0x0,0x0,
  102. 0x0,0x0,0x0,0x0,0xC0,0x40,0x46,0x89,0x8B,0x13,0x15,0x25,0x29,0x7A,0x4A,0xC6,
  103. 0xEA,0x9A,0xDC,0xDE,0xC7,0x63,0x1,0x41,0xE1,0xB1,0xB0,0xB0,0x10,0x10,0x14,0x9E,
  104. 0xDE,0x79,0x10,0x0,0x8,0x8,0x8,0x18,0xE8,0x68,0x44,0xC4,0x84,0x84,0x4,0x0,
  105. 0x0,0x2,0x2,0x2,0x2,0x3,0x3,0x3,0x2,0x0,0x0,0x1,0x1,0x0,0x0,0x80,
  106. 0x80,0xC0,0xC0,0xE0,0x60,0x50,0x38,0x38,0x14,0xA,0x5,0x3,0x1,0x0,0x0,0x0
  107. };

  108. // i2c协议的开始位
  109. void i2c_start()
  110. {
  111.         bflb_gpio_set(gpio, SDA);
  112.         waittime(1);
  113.         bflb_gpio_set(gpio, SCL);
  114.         waittime(1);
  115.         bflb_gpio_reset(gpio, SDA);
  116.         waittime(1);
  117.         bflb_gpio_reset(gpio, SCL);
  118. }
  119. // i2c协议的结束位
  120. void i2c_stop()
  121. {
  122.         bflb_gpio_reset(gpio, SDA);
  123.         waittime(1);
  124.         bflb_gpio_set(gpio, SCL);
  125.         waittime(1);
  126.         bflb_gpio_set(gpio, SDA);
  127. }
  128. // i2c协议发送一个字节
  129. void send_byte(uint8_t dat)
  130. {
  131.         uint8_t i;
  132.         for (i = 0; i<8; i++)
  133.         {
  134.                 if (dat & 0x80)
  135.                 {
  136.                         bflb_gpio_set(gpio, SDA);
  137.                 }
  138.                 else
  139.                 {
  140.                         bflb_gpio_reset(gpio, SDA);
  141.                 }
  142.                 waittime(1);
  143.                 bflb_gpio_set(gpio, SCL);
  144.                 waittime(1);
  145.                 bflb_gpio_reset(gpio, SCL);
  146.                 waittime(1);
  147.                 dat <<= 1;
  148.         }
  149.         bflb_gpio_set(gpio, SDA);
  150.         waittime(1);
  151.         bflb_gpio_set(gpio, SCL);
  152.         waittime(1);
  153.         bflb_gpio_reset(gpio, SCL);
  154.         waittime(1);
  155. }

  156. // 发送一帧数据
  157. void oled_wr_byte(uint8_t dat, uint8_t mode)
  158. {
  159.         i2c_start();
  160.         send_byte(addr);
  161.         mode ? send_byte(0x40) : send_byte(0x00);
  162.         send_byte(dat);
  163.         i2c_stop();
  164. }
  165. // 发送一帧命令数据
  166. void oled_cmd(uint8_t cmd)
  167. {
  168.         printf("cmd:%d\r\n", cmd);
  169.         oled_wr_byte(cmd, 0);
  170. }
  171. // 发送一帧Data数据
  172. void oled_data(uint8_t dat)
  173. {
  174.         oled_wr_byte(dat, 1);
  175. }
  176. // 发送定位到页的命令
  177. void page_set(uint8_t page)
  178. {
  179.         oled_cmd(0xb0 + page);
  180. }
  181. // 发送定位到列的命令
  182. void column_set(uint8_t col)
  183. {
  184.         oled_cmd(0x10 | (col >> 4));
  185.         oled_cmd(0x00 | (col & 0x0f));
  186. }
  187. // 清屏,就是把填满数据0
  188. void oled_clear()
  189. {
  190.         uint8_t page,col;
  191.         for (page = 0; page < 8; ++page)
  192.         {
  193.                 page_set(page);
  194.                 column_set(0);
  195.                 for (col = 0; col < 128; ++col)
  196.                 {
  197.                         oled_data(0x00);
  198.                 }
  199.         }
  200. }
  201. // 清屏,就是把填满数据1
  202. void oled_full()
  203. {
  204.         uint8_t page,col;
  205.         for (page = 0; page < 8; ++page)
  206.         {
  207.                 page_set(page);
  208.                 column_set(0);
  209.                 for (col = 0; col < 128; ++col)
  210.                 {
  211.                         oled_data(0xff);
  212.                 }
  213.         }
  214. }
  215. // 显示图片
  216. void oled_display(const uint8_t *ptr_pic)
  217. {
  218.         uint8_t page,col;
  219.         for (page = 0; page < 8; ++page)
  220.         {
  221.                 page_set(page);
  222.                 column_set(0);
  223.                 for (col = 0; col < 128; ++col)
  224.                 {
  225.                         oled_data(*ptr_pic++);
  226.                 }
  227.         }
  228. }
  229. // 显示图片,1和0反转,就是反色
  230. void oled_display_r(const uint8_t *ptr_pic)
  231. {
  232.         uint8_t page,col,data;
  233.         for (page = 0; page < 8; ++page)
  234.         {
  235.                 page_set(page);
  236.                 column_set(0);
  237.                 for (col = 0; col < 128; ++col)
  238.                 {
  239.                         data=*ptr_pic++;
  240.                         data=~data;
  241.                         oled_data(data);
  242.                 }
  243.         }
  244. }
  245. // 初始化,点亮屏幕,按手册执行一些列命令即可,有些命令不是必要的
  246. void init_display()
  247. {
  248.         uint8_t cmds[25] =
  249.         {
  250.        0xAE,//关闭显示
  251.        0xD5,//设置时钟分频因子,震荡频率
  252.        0x80,  //[3:0],分频因子;[7:4],震荡频率
  253.        0xA8,//设置驱动路数
  254.        0X3F,//默认0X3F(1/64)
  255.        0xD3,//设置显示偏移
  256.        0X00,//默认为0
  257.        0x40,//设置显示开始行 [5:0],行数.                              
  258.        0x8D,//电荷泵设置
  259.        0x14,//bit2,开启/关闭
  260.        0x20,//设置内存地址模式
  261.        0x02,//[1:0],00,列地址模式;01,行地址模式;10,页地址模式;默认10;
  262.        0xA1,//段重定义设置,bit0:0,0->0;1,0->127;
  263.        0xC8,//设置COM扫描方向;bit3:0,普通模式;1,重定义模式 COM[N-1]->COM0;N:驱动路数
  264.        0xDA,//设置COM硬件引脚配置
  265.        0x12,//[5:4]配置            
  266.        0x81,//对比度设置
  267.        0xEF,//1~255;默认0X7F (亮度设置,越大越亮)
  268.        0xD9,//设置预充电周期
  269.        0xf1,//[3:0],PHASE 1;[7:4],PHASE 2;
  270.        0xDB,//设置VCOMH 电压倍率
  271.        0x30,//[6:4] 000,0.65*vcc;001,0.77*vcc;011,0.83*vcc;
  272.        0xA4,//全局显示开启;bit0:1,开启;0,关闭;(白屏/黑屏)
  273.        0xA6,//设置显示方式;bit0:1,反相显示;0,正常显示        
  274.        0xAF,//开启显示     
  275.         };
  276.         uint8_t i;
  277.         for (i = 0; i < 25; ++i)
  278.         {
  279.                 oled_cmd(cmds[i]);
  280.         }
  281.         sleep(1);
  282. }
  283. void led_run(void* param)
  284. {
  285.     gpio = bflb_device_get_by_name("gpio");
  286.     /* I2C0_SDA */
  287.     bflb_gpio_init(gpio, SDA, GPIO_OUTPUT | GPIO_PULLUP);
  288.     /* I2C0_SCL */
  289.     bflb_gpio_init(gpio, SCL, GPIO_OUTPUT | GPIO_PULLUP);
  290.         // 初始化,点亮屏幕
  291.         // 图片轮播
  292.         init_display();
  293.         point= &picture_tab[0];
  294.         while (true)
  295.         {
  296.                 sleep(3);
  297.                 oled_display(point);
  298.                 sleep(3);
  299.                 oled_display_r(point);
  300.         }
  301.         
  302. }
  303. int main(void)
  304. {
  305.     board_init();
  306.         xTaskCreate(led_run, (char*)"led_run", 1024*4, NULL, 1, NULL);
  307.         vTaskStartScheduler();
  308. }
复制代码
代码好像被吞了,我再试试
回复 支持 反对

使用道具 举报

干簧管 | 2023-11-27 21:46:20 | 显示全部楼层
加油
回复

使用道具 举报

WT_0213 | 2023-11-28 08:44:19 | 显示全部楼层
二次编辑容易出现这个问题
回复 支持 反对

使用道具 举报

lazy | 2023-11-28 09:28:27 | 显示全部楼层
写的很好
回复

使用道具 举报

干簧管 | 2023-11-28 09:29:47 | 显示全部楼层
打卡
回复

使用道具 举报

496199544 | 2023-11-28 16:41:20 | 显示全部楼层
学习
回复

使用道具 举报

lclight | 2023-11-29 09:02:11 | 显示全部楼层
WT_0213 发表于 2023-11-28 08:44
二次编辑容易出现这个问题

下次就有经验了
回复 支持 反对

使用道具 举报

干簧管 | 2023-11-29 09:06:41 | 显示全部楼层
打卡
回复

使用道具 举报

lclight | 2023-11-29 09:13:58 | 显示全部楼层
回复 支持 反对

使用道具 举报

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

本版积分规则