这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » Let'sdo2025第二期活动[智能手环DIY活动](过程贴)

共1条 1/1 1 跳转至

Let'sdo2025第二期活动[智能手环DIY活动](过程贴)

菜鸟
2025-10-14 07:20:09     打赏

        我们将使用MAX78000的I2C来驱动SSD1306,根据原理图得知I2C1已经连接了一个传感器,好在它还有额外的引出PIN,现在使用杜邦线将SSD1306连接到对应的PIN上。

image.png


然后打开Example下的I2C_Scan的代码,可以根据代码中发现(或者原理图)其中定义的I2CPin 为16和17,如果烧录上述Demo的话,其扫描到的I2C地址为0x3C

image.png

然后我们可以从网上查找现成的SSD1306驱动并且将其I2C的实现修改为MAX78000实现即可。如下所示。

view plaincopy to clipboardprint?
  1. #ifndef SSD1306_H  

  2. #define SSD1306_H  

  3.   

  4. #include <stdint.h>  

  5.   

  6. #define SSD1306_ADDR 0x3C  

  7. #define SSD1306_WIDTH 128  

  8. #define SSD1306_HEIGHT 64  

  9. #define SSD1306_PAGE_NUM (SSD1306_HEIGHT / 8)  

  10.   

  11. #define SSD1306_COMMAND 0x00  

  12. #define SSD1306_DATA 0x40  

  13.   

  14. #ifdef __cplusplus  

  15. extern "C"  

  16. {  

  17. #endif  

  18.   

  19.     // 初始化 SSD1306  

  20.     void SSD1306_Init(void);  

  21.   

  22.     // 清屏  

  23.     void SSD1306_Clear(void);  

  24.   

  25.     // 显示测试图案  

  26.     void SSD1306_DisplayDemo(void);  

  27.   

  28.     // 显示缓冲区数据  

  29.     void SSD1306_DisplayFrame(uint8_t *buffer);  

  30.   

  31.     // 打印字符串(支持 6x8 ASCII)  

  32.     void SSD1306_Print(uint8_t x, uint8_t page, const char *str);  

  33.   

  34.     // 全屏缓冲区  

  35.     extern uint8_t SSD1306_Buffer[SSD1306_PAGE_NUM * SSD1306_WIDTH];  

  36.   

  37.     // 打印整数  

  38.     void SSD1306_PrintInt(uint8_t x, uint8_t page, int32_t num);  

  39.   

  40.     // 打印浮点数  

  41.     void SSD1306_PrintFloat(uint8_t x, uint8_t page, float num, uint8_t decimals);  

  42.   

  43. #ifdef __cplusplus  

  44. }  

  45. #endif  

  46.   

  47. #endif // SSD1306_H  


然后便是对应的C文件

view plaincopy to clipboardprint?
  1. #include "ssd1306.h"  

  2. #include "i2c.h"  

  3. #include "mxc_device.h"  

  4. #include "mxc_delay.h"  

  5. #include <string.h>  

  6. #include <stdio.h>  

  7.   

  8. // 6x8 ASCII 字体表  

  9. static const uint8_t Font6x8[95][6] = {  

  10.     {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // ' '  

  11.     {0x00, 0x00, 0x5F, 0x00, 0x00, 0x00}, // '!'  

  12.     {0x00, 0x07, 0x00, 0x07, 0x00, 0x00}, // '"'  

  13.     {0x14, 0x7F, 0x14, 0x7F, 0x14, 0x00}, // '#'  

  14.     {0x24, 0x2A, 0x7F, 0x2A, 0x12, 0x00}, // '$'  

  15.     {0x23, 0x13, 0x08, 0x64, 0x62, 0x00}, // '%'  

  16.     {0x36, 0x49, 0x55, 0x22, 0x50, 0x00}, // '&'  

  17.     {0x00, 0x05, 0x03, 0x00, 0x00, 0x00}, // '''  

  18.     {0x00, 0x1C, 0x22, 0x41, 0x00, 0x00}, // '('  

  19.     {0x00, 0x41, 0x22, 0x1C, 0x00, 0x00}, // ')'  

  20.     {0x14, 0x08, 0x3E, 0x08, 0x14, 0x00}, // '*'  

  21.     {0x08, 0x08, 0x3E, 0x08, 0x08, 0x00}, // '+'  

  22.     {0x00, 0x50, 0x30, 0x00, 0x00, 0x00}, // ','  

  23.     {0x08, 0x08, 0x08, 0x08, 0x08, 0x00}, // '-'  

  24.     {0x00, 0x60, 0x60, 0x00, 0x00, 0x00}, // '.'  

  25.     {0x20, 0x10, 0x08, 0x04, 0x02, 0x00}, // '/'  

  26.     {0x3E, 0x51, 0x49, 0x45, 0x3E, 0x00}, // '0'  

  27.     {0x00, 0x42, 0x7F, 0x40, 0x00, 0x00}, // '1'  

  28.     {0x42, 0x61, 0x51, 0x49, 0x46, 0x00}, // '2'  

  29.     {0x21, 0x41, 0x45, 0x4B, 0x31, 0x00}, // '3'  

  30.     {0x18, 0x14, 0x12, 0x7F, 0x10, 0x00}, // '4'  

  31.     {0x27, 0x45, 0x45, 0x45, 0x39, 0x00}, // '5'  

  32.     {0x3C, 0x4A, 0x49, 0x49, 0x30, 0x00}, // '6'  

  33.     {0x01, 0x71, 0x09, 0x05, 0x03, 0x00}, // '7'  

  34.     {0x36, 0x49, 0x49, 0x49, 0x36, 0x00}, // '8'  

  35.     {0x06, 0x49, 0x49, 0x29, 0x1E, 0x00}, // '9'  

  36.     {0x00, 0x36, 0x36, 0x00, 0x00, 0x00}, // ':'  

  37.     {0x00, 0x56, 0x36, 0x00, 0x00, 0x00}, // ';'  

  38.     {0x08, 0x14, 0x22, 0x41, 0x00, 0x00}, // '<'  

  39.     {0x14, 0x14, 0x14, 0x14, 0x14, 0x00}, // '='  

  40.     {0x00, 0x41, 0x22, 0x14, 0x08, 0x00}, // '>'  

  41.     {0x02, 0x01, 0x51, 0x09, 0x06, 0x00}, // '?'  

  42.     {0x32, 0x49, 0x79, 0x41, 0x3E, 0x00}, // '@'  

  43.     {0x7E, 0x11, 0x11, 0x11, 0x7E, 0x00}, // 'A'  

  44.     {0x7F, 0x49, 0x49, 0x49, 0x36, 0x00}, // 'B'  

  45.     {0x3E, 0x41, 0x41, 0x41, 0x22, 0x00}, // 'C'  

  46.     {0x7F, 0x41, 0x41, 0x22, 0x1C, 0x00}, // 'D'  

  47.     {0x7F, 0x49, 0x49, 0x49, 0x41, 0x00}, // 'E'  

  48.     {0x7F, 0x09, 0x09, 0x09, 0x01, 0x00}, // 'F'  

  49.     {0x3E, 0x41, 0x49, 0x49, 0x7A, 0x00}, // 'G'  

  50.     {0x7F, 0x08, 0x08, 0x08, 0x7F, 0x00}, // 'H'  

  51.     {0x00, 0x41, 0x7F, 0x41, 0x00, 0x00}, // 'I'  

  52.     {0x20, 0x40, 0x41, 0x3F, 0x01, 0x00}, // 'J'  

  53.     {0x7F, 0x08, 0x14, 0x22, 0x41, 0x00}, // 'K'  

  54.     {0x7F, 0x40, 0x40, 0x40, 0x40, 0x00}, // 'L'  

  55.     {0x7F, 0x02, 0x0C, 0x02, 0x7F, 0x00}, // 'M'  

  56.     {0x7F, 0x04, 0x08, 0x10, 0x7F, 0x00}, // 'N'  

  57.     {0x3E, 0x41, 0x41, 0x41, 0x3E, 0x00}, // 'O'  

  58.     {0x7F, 0x09, 0x09, 0x09, 0x06, 0x00}, // 'P'  

  59.     {0x3E, 0x41, 0x51, 0x21, 0x5E, 0x00}, // 'Q'  

  60.     {0x7F, 0x09, 0x19, 0x29, 0x46, 0x00}, // 'R'  

  61.     {0x46, 0x49, 0x49, 0x49, 0x31, 0x00}, // 'S'  

  62.     {0x01, 0x01, 0x7F, 0x01, 0x01, 0x00}, // 'T'  

  63.     {0x3F, 0x40, 0x40, 0x40, 0x3F, 0x00}, // 'U'  

  64.     {0x1F, 0x20, 0x40, 0x20, 0x1F, 0x00}, // 'V'  

  65.     {0x7F, 0x20, 0x18, 0x20, 0x7F, 0x00}, // 'W'  

  66.     {0x63, 0x14, 0x08, 0x14, 0x63, 0x00}, // 'X'  

  67.     {0x07, 0x08, 0x70, 0x08, 0x07, 0x00}, // 'Y'  

  68.     {0x61, 0x51, 0x49, 0x45, 0x43, 0x00}, // 'Z'  

  69.     {0x00, 0x7F, 0x41, 0x41, 0x00, 0x00}, // '['  

  70.     {0x02, 0x04, 0x08, 0x10, 0x20, 0x00}, // '\'  

  71.     {0x00, 0x41, 0x41, 0x7F, 0x00, 0x00}, // ']'  

  72.     {0x04, 0x02, 0x01, 0x02, 0x04, 0x00}, // '^'  

  73.     {0x40, 0x40, 0x40, 0x40, 0x40, 0x00}, // '_'  

  74.     {0x00, 0x01, 0x02, 0x04, 0x00, 0x00}, // '`'  

  75.     {0x20, 0x54, 0x54, 0x54, 0x78, 0x00}, // 'a'  

  76.     {0x7F, 0x48, 0x44, 0x44, 0x38, 0x00}, // 'b'  

  77.     {0x38, 0x44, 0x44, 0x44, 0x20, 0x00}, // 'c'  

  78.     {0x38, 0x44, 0x44, 0x48, 0x7F, 0x00}, // 'd'  

  79.     {0x38, 0x54, 0x54, 0x54, 0x18, 0x00}, // 'e'  

  80.     {0x08, 0x7E, 0x09, 0x01, 0x02, 0x00}, // 'f'  

  81.     {0x0C, 0x52, 0x52, 0x52, 0x3E, 0x00}, // 'g'  

  82.     {0x7F, 0x08, 0x04, 0x04, 0x78, 0x00}, // 'h'  

  83.     {0x00, 0x44, 0x7D, 0x40, 0x00, 0x00}, // 'i'  

  84.     {0x20, 0x40, 0x44, 0x3D, 0x00, 0x00}, // 'j'  

  85.     {0x7F, 0x10, 0x28, 0x44, 0x00, 0x00}, // 'k'  

  86.     {0x00, 0x41, 0x7F, 0x40, 0x00, 0x00}, // 'l'  

  87.     {0x7C, 0x04, 0x18, 0x04, 0x78, 0x00}, // 'm'  

  88.     {0x7C, 0x08, 0x04, 0x04, 0x78, 0x00}, // 'n'  

  89.     {0x38, 0x44, 0x44, 0x44, 0x38, 0x00}, // 'o'  

  90.     {0x7C, 0x14, 0x14, 0x14, 0x08, 0x00}, // 'p'  

  91.     {0x08, 0x14, 0x14, 0x18, 0x7C, 0x00}, // 'q'  

  92.     {0x7C, 0x08, 0x04, 0x04, 0x08, 0x00}, // 'r'  

  93.     {0x48, 0x54, 0x54, 0x54, 0x20, 0x00}, // 's'  

  94.     {0x04, 0x3F, 0x44, 0x40, 0x20, 0x00}, // 't'  

  95.     {0x3C, 0x40, 0x40, 0x20, 0x7C, 0x00}, // 'u'  

  96.     {0x1C, 0x20, 0x40, 0x20, 0x1C, 0x00}, // 'v'  

  97.     {0x3C, 0x40, 0x30, 0x40, 0x3C, 0x00}, // 'w'  

  98.     {0x44, 0x28, 0x10, 0x28, 0x44, 0x00}, // 'x'  

  99.     {0x0C, 0x50, 0x50, 0x50, 0x3C, 0x00}, // 'y'  

  100.     {0x44, 0x64, 0x54, 0x4C, 0x44, 0x00}, // 'z'  

  101.     {0x00, 0x08, 0x36, 0x41, 0x00, 0x00}, // '{'  

  102.     {0x00, 0x00, 0x7F, 0x00, 0x00, 0x00}, // '|'  

  103.     {0x00, 0x41, 0x36, 0x08, 0x00, 0x00}, // '}'  

  104.     {0x10, 0x08, 0x08, 0x10, 0x08, 0x00}, // '~'  

  105. };  

  106.   

  107. // 是否开启调试日志  

  108. #define SSD1306_DEBUG 0 // 1: 开启日志,0: 关闭日志  

  109.   

  110. #if SSD1306_DEBUG  

  111. #define SSD1306_LOG(fmt, ...) printf(fmt, ##__VA_ARGS__)  

  112. #else  

  113. #define SSD1306_LOG(fmt, ...) // 什么都不做  

  114. #endif  

  115.   

  116. // SSD1306 全屏缓冲区  

  117. uint8_t SSD1306_Buffer[SSD1306_PAGE_NUM * SSD1306_WIDTH];  

  118.   

  119. // I2C 写入函数,增加返回值日志  

  120. static int SSD1306_Write(uint8_t control, uint8_t *data, uint16_t len)  

  121. {  

  122.     mxc_i2c_req_t req;  

  123.     req.i2c = MXC_I2C1; // 根据你的硬件选择  

  124.     req.addr = SSD1306_ADDR;  

  125.   

  126.     uint8_t buffer[len + 1];  

  127.     buffer[0] = control;  

  128.     memcpy(buffer + 1, data, len);  

  129.   

  130.     req.tx_buf = buffer;  

  131.     req.tx_len = len + 1;  

  132.     req.rx_buf = NULL;  

  133.     req.rx_len = 0;  

  134.     req.restart = 0;  

  135.     req.callback = NULL;  

  136.   

  137.     int ret = MXC_I2C_MasterTransaction(&req);  

  138.     if (ret != 0)  

  139.     {  

  140.         SSD1306_LOG("[SSD1306] I2C Write failed, addr=0x%02X, control=0x%02X, ret=%d\n", SSD1306_ADDR, control, ret);  

  141.     }  

  142.     else  

  143.     {  

  144.         SSD1306_LOG("[SSD1306] I2C Write success, addr=0x%02X, control=0x%02X, len=%d\n", SSD1306_ADDR, control, len);  

  145.     }  

  146.     MXC_Delay(MXC_DELAY_MSEC(5)); // 给总线一些时间  

  147.     return ret;  

  148. }  

  149.   

  150. // 初始化 SSD1306,增加日志  

  151. void SSD1306_Init(void)  

  152. {  

  153.     SSD1306_LOG("[SSD1306] Init start\n");  

  154.     uint8_t init_cmds[] = {  

  155.         0xAE, 0x20, 0x00, 0xB0, 0xC8, 0x00, 0x10, 0x40,  

  156.         0x81, 0xFF, 0xA1, 0xA6, 0xA8, 0x3F, 0xA4, 0xD3, 0x00,  

  157.         0xD5, 0xF0, 0xD9, 0x22, 0xDA, 0x12, 0xDB, 0x20, 0x8D, 0x14,  

  158.         0xAF};  

  159.     int ret = SSD1306_Write(SSD1306_COMMAND, init_cmds, sizeof(init_cmds));  

  160.     if (ret != 0)  

  161.     {  

  162.         SSD1306_LOG("[SSD1306] Init failed\n");  

  163.         return;  

  164.     }  

  165.     SSD1306_Clear();  

  166.     SSD1306_LOG("[SSD1306] Init done\n");  

  167. }  

  168.   

  169. // 清屏  

  170. void SSD1306_Clear(void)  

  171. {  

  172.     memset(SSD1306_Buffer, 0x00, sizeof(SSD1306_Buffer));  

  173.     SSD1306_DisplayFrame(SSD1306_Buffer);  

  174.     SSD1306_LOG("[SSD1306] Clear screen\n");  

  175. }  

  176.   

  177. // 显示缓冲区  

  178. void SSD1306_DisplayFrame(uint8_t *buffer)  

  179. {  

  180.     for (uint8_t page = 0; page < SSD1306_PAGE_NUM; page++)  

  181.     {  

  182.         uint8_t set_page_cmds[] = {0xB0 | page, 0x00, 0x10};  

  183.         if (SSD1306_Write(SSD1306_COMMAND, set_page_cmds, sizeof(set_page_cmds)) != 0)  

  184.         {  

  185.             SSD1306_LOG("[SSD1306] Set page %d failed\n", page);  

  186.         }  

  187.         if (SSD1306_Write(SSD1306_DATA, buffer + page * SSD1306_WIDTH, SSD1306_WIDTH) != 0)  

  188.         {  

  189.             SSD1306_LOG("[SSD1306] Write page %d data failed\n", page);  

  190.         }  

  191.     }  

  192. }  

  193.   

  194. // 打印字符串  

  195. void SSD1306_Print(uint8_t x, uint8_t page, const char *str)  

  196. {  

  197.     while (*str)  

  198.     {  

  199.         if (x > SSD1306_WIDTH - 6)  

  200.         {  

  201.             x = 0;  

  202.             page++;  

  203.             if (page >= SSD1306_PAGE_NUM)  

  204.                 break;  

  205.         }  

  206.   

  207.         uint8_t c = *str;  

  208.         if (c < ' ' || c > '~')  

  209.             c = ' '// 非法字符用空格  

  210.         memcpy(&SSD1306_Buffer[page * SSD1306_WIDTH + x], Font6x8[c - ' '], 6);  

  211.   

  212.         x += 6;  

  213.         str++;  

  214.     }  

  215.     SSD1306_DisplayFrame(SSD1306_Buffer);  

  216.     SSD1306_LOG("[SSD1306] Print string done\n");  

  217. }  

  218.   

  219. // 打印整数  

  220. void SSD1306_PrintInt(uint8_t x, uint8_t page, int32_t num)  

  221. {  

  222.     char buf[12]; // 足够容纳 -2147483648\0  

  223.     sprintf(buf, "%ld", num);  

  224.     SSD1306_Print(x, page, buf);  

  225. }  

  226.   

  227. // 打印浮点数  

  228. void SSD1306_PrintFloat(uint8_t x, uint8_t page, float num, uint8_t decimals)  

  229. {  

  230.     char buf[20]; // 足够容纳浮点数  

  231.     char format[8];  

  232.     sprintf(format, "%%.%df", decimals); // 生成格式字符串,例如 "%.2f"  

  233.     sprintf(buf, format, num);  

  234.     SSD1306_Print(x, page, buf);  

  235. }  


我上述只包括了一个字库,并且显示的话不是按照Xy进行显示的,而是根据Line进行显示,这样也省去了每次计算坐标的麻烦。 缺点是不够灵活。

view plaincopy to clipboardprint?
  1. #include <stdio.h>  

  2. #include "board.h"  

  3. #include "mxc_device.h"  

  4. #include "mxc_delay.h"  

  5. #include "i2c.h"  

  6. #include "ssd1306.h"  

  7.   

  8. int main(void)  

  9. {  

  10.     printf("SSD1306 0.96 inch Example\n");  

  11.   

  12.     // 初始化 I2C  

  13.     int res = MXC_I2C_Init(MXC_I2C1, 1, 0);  

  14.     printf("I2C Init: %d\n", res);  

  15.     MXC_I2C_SetFrequency(MXC_I2C1, 400000);  

  16.     printf("I2C Frequency: %d\n", MXC_I2C_GetFrequency(MXC_I2C1));  

  17.     // 初始化 OLED  

  18.     SSD1306_Init();  

  19.   

  20.     // 清屏  

  21.     SSD1306_Clear();  

  22.   

  23.     // 打印文字  

  24.     SSD1306_Print(0, 0, "Hello MAX78000!");  

  25.     SSD1306_Print(0, 1, "SSD1306 OLED Demo");  

  26.     SSD1306_Print(0, 2, "Hello EEPW!");  

  27.     SSD1306_Print(0, 3, "Hello Let’s do !");  

  28.     SSD1306_PrintInt(0, 4, 33);  

  29.     SSD1306_PrintFloat(0, 5, 77.7, 2);  

  30.     while (1)  

  31.     {  

  32.         MXC_Delay(MXC_DELAY_MSEC(1000));  

  33.     }  

  34.   

  35.     return 0;  

  36. }  

在主函数中进行调用。 然后便可以观察到屏幕已经正常的点亮。 黄蓝屏,真的很好看!

ac3662d17430b9bbba435f8e868e26f2.jpg






关键词: 二期     智能     手环    

共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]