你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32CubeIDE的基于SPI通信OLED点亮及字符显示经验分享

[复制链接]
攻城狮Melo 发布时间:2023-4-7 15:18
一、SPI 通信技术
        显示屏(LCD、OLED)接口一般有I2C、SPI、UART、RGB、LVDS、MIPI、EDP和DP等。一般3.5寸以下的小尺寸LCD屏,显示数据量比较少,普遍采用低速串口,如I2C、SPI、UART。SPI(Serial Peripheral Interface)是全双工,同步的通信总线,以主从方式工作,这种模式通常有一个主设备和一个或多个从设备,需要至少4根线,事实上3根也可以(单向传输时,MISO、MISI取其一),节约了芯片的管脚。

        这些数据线是MISO(主设备数据输入)、MOSI(主设备数据输出)、SCLK(时钟)、CS(片选)。

(1)MISO– Master Input Slave Output,主设备数据输入,从设备数据输出;

(2)MOSI– Master Output Slave Input,主设备数据输出,从设备数据输入;

(3)SCLK – Serial Clock,时钟信号,由主设备产生;

(4)CS – Chip Select,从设备使能信号,由主设备控制。

        CS是控制芯片是否被选中的,也就是说只有片选信号为预先规定的使能信号时(高电位或低电位),对此芯片的操作才有效。。SCK提供时钟脉冲,SDI,SDO则基于此脉冲完成数据传输。


二、SPI通信参配
        本文采用的开发板是stm32L496VGT3,该开发板的OLED屏是240*240像素,采用SPI协议通讯,MCU采用4-Line SPI 的接口加上电源、重置等接口,实现 LCD 显示屏控制及输出显示,原理图如下:

2694f5640ab14349920321a185890cb4.png

         LCD 显示屏针脚定义:

7d51cd294e324ad4aa5667e93c40529c.png

         MCU连接LCD的芯片引脚定义如下:

ef70a1aa3a054715a25b762f79bbd2ce.png

         各个引脚的具体参数:

190d1b75537e45859cdab765cc9a94a1.png

三、SPI设置(cubeMx)
        在cubeIDE基于stm32L496VGT3芯片创建工程,打开界面配置(cubeMx),配置OLED屏的通信相关信息。本文是在一定基础上直接操作

        假设已经做好了时钟配置、lpusart调试输出,先直接设置OLED的SPI接口信息:

        1)开启SPI1
        本文只是纯粹的MCU向OLED屏输出信号,因此选择Transmit Only Master模式。

55dd5447240a4432a4791f1cf3fa9aba.png

         2)添加SPI1的DMA支持

949ebc104a5c44dcbff3521af2e2de0b.png

         3)开启spi1的中断功能

16dbb4ba87fc43cfb258c834c4a46e9d.png

         4)设置oled屏控制的辅助引脚、设置名称及调整配置参数

b3bd769e1cfb428883a460af666b1522.png

         5)调整SPI1配置参数

82d00ed1b91c44a5bb6bb07aa286e189.png

         6)完成配置后,点击保存或生成代码的按钮生成代码
四、SPI通信及OLED屏点亮
        在ICore目录创建oled文件夹,创建oled.h、oled.c的LCD驱动文件。

        1)辅助引脚设值
        在oled.h中加入对LCD引脚(GPIO)设值控制函数
  1. //对该位写1或0
  2. #define Data_Cmd_State(__D_C_State__)        HAL_GPIO_WritePin(LCD_DCX_GPIO_Port, LCD_DCX_Pin, (GPIO_PinState)(__D_C_State__))
  3. #define OLED_RST_State(__RST_State__)        HAL_GPIO_WritePin(LCD_RST_GPIO_Port, LCD_RST_Pin, (GPIO_PinState)(__RST_State__))
  4. #define LCD_PWR_State(__PWR_State__)        HAL_GPIO_WritePin(LCD_PWR_GPIO_Port, LCD_PWR_Pin, (GPIO_PinState)(__PWR_State__))
复制代码

        2)spi1写入数据实现
        通过调用HAL标准库的HAL_SPI_Transmit函数实现对spi1(hspi1)实现写入命令函数或数据写入函数,也提供LcdWriteDataMultiple函数一次写入多个数据
  1. /********************************************************************
  2. *
  3. *   LcdWriteReg
  4. *
  5. *         Function description:
  6. *   Sets display register
  7. */
  8. void LcdWriteReg(uint8_t Data)
  9. {
  10.           Data_Cmd_State(0);
  11.           HAL_SPI_Transmit(&hspi1, &Data, 1, 10);
  12. }

  13. /********************************************************************
  14. *
  15. *          LcdWriteData
  16. *
  17. *         Function description:
  18. *   Writes a value to a display register
  19. */
  20. void LcdWriteData(uint8_t Data)
  21. {
  22.           Data_Cmd_State(1);
  23.           HAL_SPI_Transmit(&hspi1, &Data, 1, 10);
  24. }

  25. /********************************************************************
  26. *
  27. *        LcdWriteDataMultiple
  28. *
  29. *         Function description:
  30. *   Writes multiple values to a display register.
  31. */
  32. void LcdWriteDataMultiple(uint8_t * pData, uint32_t NumItems)
  33. {
  34.           Data_Cmd_State(1);
  35.           HAL_SPI_Transmit(&hspi1, pData, NumItems, 10);
  36. }
复制代码

        3)OLED初始化指令执行
        定义OLED屏的初始化指令集及指令设置函数
  1. /* Init script function */
  2. struct OLED_function {
  3.   uint8_t cmd;
  4.   uint16_t data;
  5. };

  6. /* Init script commands */
  7. enum OLED_cmd {
  8.   OLED_START,
  9.   OLED_END,
  10.   OLED_CMD,
  11.   OLED_DATA,
  12.   OLED_DELAY
  13. };
  14. //以上可放置头文件中
  15. //以下放置源文件中
  16. //初始化命令集
  17. static struct OLED_function OLED_cfg_script[] = {
  18.   {OLED_START, OLED_START},
  19.   {OLED_CMD, 0x11},
  20.   {OLED_DELAY, 120},
  21.   {OLED_CMD, 0x36},
  22.   {OLED_DATA, 0x00},
  23.   {OLED_CMD, 0x3a},
  24.   {OLED_DATA, 0x65},
  25.   {OLED_CMD, 0xb2},
  26.   {OLED_DATA, 0x0c},
  27.   {OLED_DATA, 0x0c},
  28.   {OLED_DATA, 0x00},
  29.   {OLED_DATA, 0x33},
  30.   {OLED_DATA, 0x33},
  31.   {OLED_CMD, 0xb7},
  32.   {OLED_DATA, 0x72},
  33.   {OLED_CMD, 0xbb},
  34.   {OLED_DATA, 0x3d},
  35.   {OLED_CMD, 0xc0},
  36.   {OLED_DATA, 0x2c},
  37.   {OLED_CMD, 0xc2},
  38.   {OLED_DATA, 0x01},
  39.   {OLED_CMD, 0xc3},
  40.   {OLED_DATA, 0x19},
  41.   {OLED_CMD, 0xc4},
  42.   {OLED_DATA, 0x20},
  43.   {OLED_CMD, 0xc6},
  44.   {OLED_DATA, 0x0f},
  45.   {OLED_CMD, 0xd0},
  46.   {OLED_DATA, 0xa4},
  47.   {OLED_DATA, 0xa1},
  48.   {OLED_CMD, 0xe0},
  49.   {OLED_DATA, 0x70},
  50.   {OLED_DATA, 0x04},
  51.   {OLED_DATA, 0x08},
  52.   {OLED_DATA, 0x09},
  53.   {OLED_DATA, 0x09},
  54.   {OLED_DATA, 0x05},
  55.   {OLED_DATA, 0x2a},
  56.   {OLED_DATA, 0x33},
  57.   {OLED_DATA, 0x41},
  58.   {OLED_DATA, 0x07},
  59.   {OLED_DATA, 0x13},
  60.   {OLED_DATA, 0x13},
  61.   {OLED_DATA, 0x29},
  62.   {OLED_DATA, 0x2f},
  63.   {OLED_CMD, 0xe1},
  64.   {OLED_DATA, 0x70},
  65.   {OLED_DATA, 0x03},
  66.   {OLED_DATA, 0x09},
  67.   {OLED_DATA, 0x0a},
  68.   {OLED_DATA, 0x09},
  69.   {OLED_DATA, 0x06},
  70.   {OLED_DATA, 0x2b},
  71.   {OLED_DATA, 0x34},
  72.   {OLED_DATA, 0x41},
  73.   {OLED_DATA, 0x07},
  74.   {OLED_DATA, 0x12},
  75.   {OLED_DATA, 0x14},
  76.   {OLED_DATA, 0x28},
  77.   {OLED_DATA, 0x2e},
  78.   {OLED_CMD, 0x21},
  79.   {OLED_CMD, 0x29},
  80.   {OLED_CMD, 0x2a},
  81.   {OLED_DATA, 0x00},
  82.   {OLED_DATA, 0x00},
  83.   {OLED_DATA, 0x00},
  84.   {OLED_DATA, 0xef},
  85.   {OLED_CMD, 0x2b},
  86.   {OLED_DATA, 0x00},
  87.   {OLED_DATA, 0x00},
  88.   {OLED_DATA, 0x00},
  89.   {OLED_DATA, 0xef},
  90.   {OLED_CMD, 0x2c},
  91.   {OLED_END, OLED_END},
  92. };

  93. static void OLED_run_cfg_script()
  94. {
  95.           uint8_t data[2] = {0};
  96.           int i = 0;
  97.           int end_script = 0;

  98.           do {
  99.             switch (OLED_cfg_script[i].cmd) {
  100.             case OLED_START:
  101.               break;
  102.             case OLED_CMD:
  103.               data[0] = OLED_cfg_script[i].data & 0xff;
  104.               LcdWriteReg(data[0]);
  105.               break;
  106.             case OLED_DATA:
  107.               data[0] = OLED_cfg_script[i].data & 0xff;
  108.               LcdWriteData(data[0]);
  109.               break;
  110.             case OLED_DELAY:
  111.               HAL_Delay(OLED_cfg_script[i].data);
  112.               break;
  113.             case OLED_END:
  114.               end_script = 1;
  115.             }
  116.             i++;
  117.           } while (!end_script);
  118. }
复制代码

        4)oled初始化
        进行oled屏的初始化函数设计
  1. //olde屏重置
  2. static void OLED_reset()
  3. {
  4.           OLED_RST_State(0);
  5.           HAL_Delay(200);
  6.           OLED_RST_State(1);
  7.           HAL_Delay(150);
  8. }
  9. //oled屏初始化
  10. int OLED_init()
  11. {
  12.           LCD_PWR_State(0);//回显关闭
  13.           OLED_reset();    //屏重置
  14.           OLED_run_cfg_script();//初始化指令集依次执行脚本函数
  15.           LCD_PWR_State(1);//回显开启
  16.           OLED_display_picture();//条形码屏幕显示测试

  17.           return HAL_OK;
  18. }
复制代码

        5)oled屏幕的亮屏(条形码显示)代码
  1. #define LCD_MAX_MEM16_BLOCK             (1 << 6)
  2. #define LCD_PIXEL_PER_BLOCK             (LCD_MAX_MEM16_BLOCK >> 1)

  3. static void spec_send_fb(uint16_t color, uint16_t pixel_num)
  4. {
  5.           uint16_t real_mem[LCD_MAX_MEM16_BLOCK] = {0};

  6.           for (uint16_t i = 0; i < LCD_MAX_MEM16_BLOCK; ++i) {
  7.                   real_mem[i] = color;
  8.           }
  9.           Data_Cmd_State(GPIO_PIN_SET);
  10.           if (pixel_num <= LCD_MAX_MEM16_BLOCK) {
  11.                   LcdWriteDataMultiple((uint8_t*)real_mem, pixel_num << 1);
  12.           } else {
  13.                   uint16_t count = pixel_num / LCD_MAX_MEM16_BLOCK;
  14.                   uint16_t remain = pixel_num % LCD_MAX_MEM16_BLOCK;
  15.                   for (uint16_t i = 0; i < count; ++i) {
  16.                           LcdWriteDataMultiple((uint8_t*)real_mem, LCD_MAX_MEM16_BLOCK << 1);
  17.                   }
  18.                   LcdWriteDataMultiple((uint8_t*)real_mem, remain << 1);
  19.           }
  20. }

  21. static void OLED_display_picture(void)
  22. {
  23.   LcdWriteReg(OLED_RAMWR);
  24.   spec_send_fb(0x0, WIDTH * HEIGHT / 4);
  25.   spec_send_fb(0x1111, WIDTH * HEIGHT / 4);
  26.   spec_send_fb(0x7777, WIDTH * HEIGHT / 4);
  27.   spec_send_fb(0xeeee, WIDTH * HEIGHT / 4);
  28. }
复制代码


      6)驱动调用
        基本功能完成后,在main.c文件实现函数调用
  1.   /* USER CODE BEGIN Includes */
  2. #include "../../ICore/key/key.h"
  3. #include "../../ICore/led/led.h"
  4. #include "../../ICore/print/print.h"
  5. #include "../../ICore/usart/usart.h"
  6. #include "../../ICore/oled/oled.h"
  7. /* USER CODE END Includes */
  8. ..............................................
  9.     /* USER CODE BEGIN 2 */
  10.   ResetPrintInit(&hlpuart1);
  11.   HAL_UART_Receive_IT(&hlpuart1,(uint8_t *)&HLPUSART_NewData, 1); //再开启接收中断
  12.   HLPUSART_RX_STA = 0;
  13.   OLED_init();

  14.   set_led0_val(0);
  15.   set_led1_val(get_key0_val());
  16.   /* USER CODE END 2 */
  17.   /* USER CODE BEGIN WHILE */
  18.   while (1)
  19.   {
  20.     Toggle_led0();
  21.     /* USER CODE END WHILE */
复制代码

        7)编译加载到开发板上

376beaff564d46e2a3d52ba0dd3f70f6.png

         8)屏幕效果点亮如下:

d38922b1a0b644afa7150aa3942a6d9d.png


五、屏幕输出字符串设计
        【1】字符串编码表
        在ICore/oled目下字符串编码表ASCII.h,具体如下:
  1. /*
  2. * ASCII.h
  3. *
  4. *  Created on: Jun 11, 2022
  5. *      Author: Administrator
  6. */

  7. #ifndef OLED_ASCII_H_
  8. #define OLED_ASCII_H_

  9. // ------------------  ASCII字模的数据表 ------------------------ //
  10. // 码表从0x20~0x7e                                                //
  11. // 字库:  纵向取模下高位// (调用时要减512)
  12. // -------------------------------------------------------------- //
  13. const uint8_t ASCII_8x16[] =  {            // ASCII
  14.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // - -
  15.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,

  16.         0x00,0x00,0x38,0xFC,0xFC,0x38,0x00,0x00,  // -!-
  17.         0x00,0x00,0x00,0x0D,0x0D,0x00,0x00,0x00,

  18.         0x00,0x0E,0x1E,0x00,0x00,0x1E,0x0E,0x00,  // -"-
  19.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,

  20.         0x20,0xF8,0xF8,0x20,0xF8,0xF8,0x20,0x00,  // -#-
  21.         0x02,0x0F,0x0F,0x02,0x0F,0x0F,0x02,0x00,

  22.         0x38,0x7C,0x44,0x47,0x47,0xCC,0x98,0x00,  // -$-
  23.         0x03,0x06,0x04,0x1C,0x1C,0x07,0x03,0x00,

  24.         0x30,0x30,0x00,0x80,0xC0,0x60,0x30,0x00,  // -%-
  25.         0x0C,0x06,0x03,0x01,0x00,0x0C,0x0C,0x00,

  26.         0x80,0xD8,0x7C,0xE4,0xBC,0xD8,0x40,0x00,  // -&-
  27.         0x07,0x0F,0x08,0x08,0x07,0x0F,0x08,0x00,

  28.         0x00,0x10,0x1E,0x0E,0x00,0x00,0x00,0x00,  // -'-
  29.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,

  30.         0x00,0x00,0xF0,0xF8,0x0C,0x04,0x00,0x00,  // -(-
  31.         0x00,0x00,0x03,0x07,0x0C,0x08,0x00,0x00,

  32.         0x00,0x00,0x04,0x0C,0xF8,0xF0,0x00,0x00,  // -)-
  33.         0x00,0x00,0x08,0x0C,0x07,0x03,0x00,0x00,

  34.         0x80,0xA0,0xE0,0xC0,0xC0,0xE0,0xA0,0x80,  // -*-
  35.         0x00,0x02,0x03,0x01,0x01,0x03,0x02,0x00,

  36.         0x00,0x80,0x80,0xE0,0xE0,0x80,0x80,0x00,  // -+-
  37.         0x00,0x00,0x00,0x03,0x03,0x00,0x00,0x00,

  38.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // -,-
  39.         0x00,0x00,0x10,0x1E,0x0E,0x00,0x00,0x00,

  40.         0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00,  // ---
  41.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,

  42.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // -.-
  43.         0x00,0x00,0x00,0x0C,0x0C,0x00,0x00,0x00,

  44.         0x00,0x00,0x00,0x80,0xC0,0x60,0x30,0x00,  // -/-
  45.         0x0C,0x06,0x03,0x01,0x00,0x00,0x00,0x00,

  46.         0xF8,0xFC,0x04,0xC4,0x24,0xFC,0xF8,0x00,  // -0-
  47.         0x07,0x0F,0x09,0x08,0x08,0x0F,0x07,0x00,

  48.         0x00,0x10,0x18,0xFC,0xFC,0x00,0x00,0x00,  // -1-
  49.         0x00,0x08,0x08,0x0F,0x0F,0x08,0x08,0x00,

  50.         0x08,0x0C,0x84,0xC4,0x64,0x3C,0x18,0x00,  // -2-
  51.         0x0E,0x0F,0x09,0x08,0x08,0x0C,0x0C,0x00,

  52.         0x08,0x0C,0x44,0x44,0x44,0xFC,0xB8,0x00,  // -3-
  53.         0x04,0x0C,0x08,0x08,0x08,0x0F,0x07,0x00,

  54.         0xC0,0xE0,0xB0,0x98,0xFC,0xFC,0x80,0x00,  // -4-
  55.         0x00,0x00,0x00,0x08,0x0F,0x0F,0x08,0x00,

  56.         0x7C,0x7C,0x44,0x44,0xC4,0xC4,0x84,0x00,  // -5-
  57.         0x04,0x0C,0x08,0x08,0x08,0x0F,0x07,0x00,

  58.         0xF0,0xF8,0x4C,0x44,0x44,0xC0,0x80,0x00,  // -6-
  59.         0x07,0x0F,0x08,0x08,0x08,0x0F,0x07,0x00,

  60.         0x0C,0x0C,0x04,0x84,0xC4,0x7C,0x3C,0x00,  // -7-
  61.         0x00,0x00,0x0F,0x0F,0x00,0x00,0x00,0x00,

  62.         0xB8,0xFC,0x44,0x44,0x44,0xFC,0xB8,0x00,  // -8-
  63.         0x07,0x0F,0x08,0x08,0x08,0x0F,0x07,0x00,

  64.         0x38,0x7C,0x44,0x44,0x44,0xFC,0xF8,0x00,  // -9-
  65.         0x00,0x08,0x08,0x08,0x0C,0x07,0x03,0x00,

  66.         0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,  // -:-
  67.         0x00,0x00,0x00,0x06,0x06,0x00,0x00,0x00,

  68.         0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,  // -;-
  69.         0x00,0x00,0x08,0x0E,0x06,0x00,0x00,0x00,

  70.         0x00,0x80,0xC0,0x60,0x30,0x18,0x08,0x00,  // -<-
  71.         0x00,0x00,0x01,0x03,0x06,0x0C,0x08,0x00,

  72.         0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00,  // -=-
  73.         0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x00,

  74.         0x00,0x08,0x18,0x30,0x60,0xC0,0x80,0x00,  // ->-
  75.         0x00,0x08,0x0C,0x06,0x03,0x01,0x00,0x00,

  76.         0x18,0x1C,0x04,0xC4,0xE4,0x3C,0x18,0x00,  // -?-
  77.         0x00,0x00,0x00,0x0D,0x0D,0x00,0x00,0x00,

  78.         0xF0,0xF8,0x08,0xC8,0xC8,0xF8,0xF0,0x00,  // -@-
  79.         0x07,0x0F,0x08,0x0B,0x0B,0x0B,0x01,0x00,

  80.         0xE0,0xF0,0x98,0x8C,0x98,0xF0,0xE0,0x00,  // -A-
  81.         0x0F,0x0F,0x00,0x00,0x00,0x0F,0x0F,0x00,

  82.         0x04,0xFC,0xFC,0x44,0x44,0xFC,0xB8,0x00,  // -B-
  83.         0x08,0x0F,0x0F,0x08,0x08,0x0F,0x07,0x00,

  84.         0xF0,0xF8,0x0C,0x04,0x04,0x0C,0x18,0x00,  // -C-
  85.         0x03,0x07,0x0C,0x08,0x08,0x0C,0x06,0x00,

  86.         0x04,0xFC,0xFC,0x04,0x0C,0xF8,0xF0,0x00,  // -D-
  87.         0x08,0x0F,0x0F,0x08,0x0C,0x07,0x03,0x00,

  88.         0x04,0xFC,0xFC,0x44,0xE4,0x0C,0x1C,0x00,  // -E-
  89.         0x08,0x0F,0x0F,0x08,0x08,0x0C,0x0E,0x00,

  90.         0x04,0xFC,0xFC,0x44,0xE4,0x0C,0x1C,0x00,  // -F-
  91.         0x08,0x0F,0x0F,0x08,0x00,0x00,0x00,0x00,

  92.         0xF0,0xF8,0x0C,0x84,0x84,0x8C,0x98,0x00,  // -G-
  93.         0x03,0x07,0x0C,0x08,0x08,0x07,0x0F,0x00,

  94.         0xFC,0xFC,0x40,0x40,0x40,0xFC,0xFC,0x00,  // -H-
  95.         0x0F,0x0F,0x00,0x00,0x00,0x0F,0x0F,0x00,

  96.         0x00,0x00,0x04,0xFC,0xFC,0x04,0x00,0x00,  // -I-
  97.         0x00,0x00,0x08,0x0F,0x0F,0x08,0x00,0x00,

  98.         0x00,0x00,0x00,0x04,0xFC,0xFC,0x04,0x00,  // -J-
  99.         0x07,0x0F,0x08,0x08,0x0F,0x07,0x00,0x00,

  100.         0x04,0xFC,0xFC,0xC0,0xF0,0x3C,0x0C,0x00,  // -K-
  101.         0x08,0x0F,0x0F,0x00,0x01,0x0F,0x0E,0x00,

  102.         0x04,0xFC,0xFC,0x04,0x00,0x00,0x00,0x00,  // -L-
  103.         0x08,0x0F,0x0F,0x08,0x08,0x0C,0x0E,0x00,

  104.         0xFC,0xFC,0x38,0x70,0x38,0xFC,0xFC,0x00,  // -M-
  105.         0x0F,0x0F,0x00,0x00,0x00,0x0F,0x0F,0x00,

  106.         0xFC,0xFC,0x38,0x70,0xE0,0xFC,0xFC,0x00,  // -N-
  107.         0x0F,0x0F,0x00,0x00,0x00,0x0F,0x0F,0x00,

  108.         0xF0,0xF8,0x0C,0x04,0x0C,0xF8,0xF0,0x00,  // -O-
  109.         0x03,0x07,0x0C,0x08,0x0C,0x07,0x03,0x00,

  110.         0x04,0xFC,0xFC,0x44,0x44,0x7C,0x38,0x00,  // -P-
  111.         0x08,0x0F,0x0F,0x08,0x00,0x00,0x00,0x00,

  112.         0xF8,0xFC,0x04,0x04,0x04,0xFC,0xF8,0x00,  // -Q-
  113.         0x07,0x0F,0x08,0x0E,0x3C,0x3F,0x27,0x00,

  114.         0x04,0xFC,0xFC,0x44,0xC4,0xFC,0x38,0x00,  // -R-
  115.         0x08,0x0F,0x0F,0x00,0x00,0x0F,0x0F,0x00,

  116.         0x18,0x3C,0x64,0x44,0xC4,0x9C,0x18,0x00,  // -S-
  117.         0x06,0x0E,0x08,0x08,0x08,0x0F,0x07,0x00,

  118.         0x00,0x1C,0x0C,0xFC,0xFC,0x0C,0x1C,0x00,  // -T-
  119.         0x00,0x00,0x08,0x0F,0x0F,0x08,0x00,0x00,

  120.         0xFC,0xFC,0x00,0x00,0x00,0xFC,0xFC,0x00,  // -U-
  121.         0x07,0x0F,0x08,0x08,0x08,0x0F,0x07,0x00,

  122.         0xFC,0xFC,0x00,0x00,0x00,0xFC,0xFC,0x00,  // -V-
  123.         0x01,0x03,0x06,0x0C,0x06,0x03,0x01,0x00,

  124.         0xFC,0xFC,0x00,0x80,0x00,0xFC,0xFC,0x00,  // -W-
  125.         0x03,0x0F,0x0E,0x03,0x0E,0x0F,0x03,0x00,

  126.         0x0C,0x3C,0xF0,0xC0,0xF0,0x3C,0x0C,0x00,  // -X-
  127.         0x0C,0x0F,0x03,0x00,0x03,0x0F,0x0C,0x00,

  128.         0x00,0x3C,0x7C,0xC0,0xC0,0x7C,0x3C,0x00,  // -Y-
  129.         0x00,0x00,0x08,0x0F,0x0F,0x08,0x00,0x00,

  130.         0x1C,0x0C,0x84,0xC4,0x64,0x3C,0x1C,0x00,  // -Z-
  131.         0x0E,0x0F,0x09,0x08,0x08,0x0C,0x0E,0x00,

  132.         0x00,0x00,0xFC,0xFC,0x04,0x04,0x00,0x00,  // -[-
  133.         0x00,0x00,0x0F,0x0F,0x08,0x08,0x00,0x00,

  134.         0x38,0x70,0xE0,0xC0,0x80,0x00,0x00,0x00,  // -\-
  135.         0x00,0x00,0x00,0x01,0x03,0x07,0x0E,0x00,

  136.         0x00,0x00,0x04,0x04,0xFC,0xFC,0x00,0x00,  // -]-
  137.         0x00,0x00,0x08,0x08,0x0F,0x0F,0x00,0x00,

  138.         0x08,0x0C,0x06,0x03,0x06,0x0C,0x08,0x00,  // -^-
  139.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,

  140.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // -_-
  141.         0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,

  142.         0x00,0x00,0x03,0x07,0x04,0x00,0x00,0x00,  // -`-
  143.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,

  144.         0x00,0xA0,0xA0,0xA0,0xE0,0xC0,0x00,0x00,  // -a-
  145.         0x07,0x0F,0x08,0x08,0x07,0x0F,0x08,0x00,

  146.         0x04,0xFC,0xFC,0x20,0x60,0xC0,0x80,0x00,  // -b-
  147.         0x08,0x0F,0x07,0x08,0x08,0x0F,0x07,0x00,

  148.         0xC0,0xE0,0x20,0x20,0x20,0x60,0x40,0x00,  // -c-
  149.         0x07,0x0F,0x08,0x08,0x08,0x0C,0x04,0x00,

  150.         0x80,0xC0,0x60,0x24,0xFC,0xFC,0x00,0x00,  // -d-
  151.         0x07,0x0F,0x08,0x08,0x07,0x0F,0x08,0x00,

  152.         0xC0,0xE0,0xA0,0xA0,0xA0,0xE0,0xC0,0x00,  // -e-
  153.         0x07,0x0F,0x08,0x08,0x08,0x0C,0x04,0x00,

  154.         0x40,0xF8,0xFC,0x44,0x0C,0x18,0x00,0x00,  // -f-
  155.         0x08,0x0F,0x0F,0x08,0x00,0x00,0x00,0x00,

  156.         0xC0,0xE0,0x20,0x20,0xC0,0xE0,0x20,0x00,  // -g-
  157.         0x27,0x6F,0x48,0x48,0x7F,0x3F,0x00,0x00,

  158.         0x04,0xFC,0xFC,0x40,0x20,0xE0,0xC0,0x00,  // -h-
  159.         0x08,0x0F,0x0F,0x00,0x00,0x0F,0x0F,0x00,

  160.         0x00,0x00,0x20,0xEC,0xEC,0x00,0x00,0x00,  // -i-
  161.         0x00,0x00,0x08,0x0F,0x0F,0x08,0x00,0x00,

  162.         0x00,0x00,0x00,0x00,0x20,0xEC,0xEC,0x00,  // -j-
  163.         0x00,0x30,0x70,0x40,0x40,0x7F,0x3F,0x00,

  164.         0x04,0xFC,0xFC,0x80,0xC0,0x60,0x20,0x00,  // -k-
  165.         0x08,0x0F,0x0F,0x01,0x03,0x0E,0x0C,0x00,

  166.         0x00,0x00,0x04,0xFC,0xFC,0x00,0x00,0x00,  // -l-
  167.         0x00,0x00,0x08,0x0F,0x0F,0x08,0x00,0x00,

  168.         0xE0,0xE0,0x60,0xC0,0x60,0xE0,0xC0,0x00,  // -m-
  169.         0x0F,0x0F,0x00,0x0F,0x00,0x0F,0x0F,0x00,

  170.         0x20,0xE0,0xC0,0x20,0x20,0xE0,0xC0,0x00,  // -n-
  171.         0x00,0x0F,0x0F,0x00,0x00,0x0F,0x0F,0x00,

  172.         0xC0,0xE0,0x20,0x20,0x20,0xE0,0xC0,0x00,  // -o-
  173.         0x07,0x0F,0x08,0x08,0x08,0x0F,0x07,0x00,

  174.         0x20,0xE0,0xC0,0x20,0x20,0xE0,0xC0,0x00,  // -p-
  175.         0x40,0x7F,0x7F,0x48,0x08,0x0F,0x07,0x00,

  176.         0xC0,0xE0,0x20,0x20,0xC0,0xE0,0x20,0x00,  // -q-
  177.         0x07,0x0F,0x08,0x48,0x7F,0x7F,0x40,0x00,

  178.         0x20,0xE0,0xC0,0x60,0x20,0x60,0xC0,0x00,  // -r-
  179.         0x08,0x0F,0x0F,0x08,0x00,0x00,0x00,0x00,

  180.         0x40,0xE0,0xA0,0x20,0x20,0x60,0x40,0x00,  // -s-
  181.         0x04,0x0C,0x09,0x09,0x0B,0x0E,0x04,0x00,

  182.         0x20,0x20,0xF8,0xFC,0x20,0x20,0x00,0x00,  // -t-
  183.         0x00,0x00,0x07,0x0F,0x08,0x0C,0x04,0x00,

  184.         0xE0,0xE0,0x00,0x00,0xE0,0xE0,0x00,0x00,  // -u-
  185.         0x07,0x0F,0x08,0x08,0x07,0x0F,0x08,0x00,

  186.         0x00,0xE0,0xE0,0x00,0x00,0xE0,0xE0,0x00,  // -v-
  187.         0x00,0x03,0x07,0x0C,0x0C,0x07,0x03,0x00,

  188.         0xE0,0xE0,0x00,0x00,0x00,0xE0,0xE0,0x00,  // -w-
  189.         0x07,0x0F,0x0C,0x07,0x0C,0x0F,0x07,0x00,

  190.         0x20,0x60,0xC0,0x80,0xC0,0x60,0x20,0x00,  // -x-
  191.         0x08,0x0C,0x07,0x03,0x07,0x0C,0x08,0x00,

  192.         0xE0,0xE0,0x00,0x00,0x00,0xE0,0xE0,0x00,  // -y-
  193.         0x47,0x4F,0x48,0x48,0x68,0x3F,0x1F,0x00,

  194.         0x60,0x60,0x20,0xA0,0xE0,0x60,0x20,0x00,  // -z-
  195.         0x0C,0x0E,0x0B,0x09,0x08,0x0C,0x0C,0x00,

  196.         0x00,0x40,0x40,0xF8,0xBC,0x04,0x04,0x00,  // -{-
  197.         0x00,0x00,0x00,0x07,0x0F,0x08,0x08,0x00,

  198.         0x00,0x00,0x00,0xBC,0xBC,0x00,0x00,0x00,  // -|-
  199.         0x00,0x00,0x00,0x0F,0x0F,0x00,0x00,0x00,

  200.         0x00,0x04,0x04,0xBC,0xF8,0x40,0x40,0x00,  // -}-
  201.         0x00,0x08,0x08,0x0F,0x07,0x00,0x00,0x00,

  202.         0x08,0x0C,0x04,0x0C,0x08,0x0C,0x04,0x00,  // -~-
  203.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,

  204.         0x80,0xC0,0x60,0x30,0x60,0xC0,0x80,0x00,  // --
  205.         0x07,0x07,0x04,0x04,0x04,0x07,0x07,0x00,
  206. };

  207. #endif /* OLED_ASCII_H_ */
复制代码

【2】将创建屏幕打印函数,输出显示字符串能力
        (1)首选了解ASCII_8x16字库表如何使用的,例如我们取"!"为例:
  1. !16个8bit的字段的二进制表示如下
  2. 0X00     0 0 0 0 0 0 0 0
  3. 0X00     0 0 0 0 0 0 0 0
  4. 0X38     0 0 1 1 1 0 0 0
  5. 0XFC     1 1 1 1 1 1 0 0
  6. 0XFC     1 1 1 1 1 1 0 0
  7. 0X38     0 0 1 1 1 0 0 0
  8. 0X00     0 0 0 0 0 0 0 0
  9. 0X00     0 0 0 0 0 0 0 0

  10. 0X00     0 0 0 0 0 0 0 0
  11. 0X00     0 0 0 0 0 0 0 0
  12. 0X00     0 0 0 0 0 0 0 0
  13. 0X0D     0 0 0 0 1 1 0 1
  14. 0X0D     0 0 0 0 1 1 0 1
  15. 0X00     0 0 0 0 0 0 0 0
  16. 0X00     0 0 0 0 0 0 0 0
  17. 0X00     0 0 0 0 0 0 0 0
复制代码

        (2)将划分为前8*8和后8*8的的二进制矩阵,将8*8矩阵做逆时针(90度)翻转,将翻转后矩阵进行紧凑(去掉空格),这些“1”组成了一个大的“!”字符如下:
  1. //将8*8二进制矩阵翻转
  2. 0X000X000X380XFC0XFC0X380X000X00
  3. 0        0        0        0        0        0        0        0
  4. 0        0        0        0        0        0        0        0
  5. 0        0        0        1        1        0        0        0
  6. 0        0        1        1        1        1        0        0
  7. 0        0        1        1        1        1        0        0
  8. 0        0        1        1        1        1        0        0
  9. 0        0        0        1        1        0        0        0
  10. 0        0        0        1        1        0        0        0
  11. 0X000X000X000X0D0X0D0X000X000X00
  12. 0        0        0        1        1        0        0        0
  13. 0        0        0        0        0        0        0        0
  14. 0        0        0        1        1        0        0        0
  15. 0        0        0        1        1        0        0        0
  16. 0        0        0        0        0        0        0        0
  17. 0        0        0        0        0        0        0        0
  18. 0        0        0        0        0        0        0        0
  19. 0        0        0        0        0        0        0        0

  20. 将上述矩阵进行紧凑(去掉空格),这些“1”组成了一个大的“!”字符
  21. 00000000
  22. 00000000
  23. 00011000
  24. 00111100
  25. 00111100
  26. 00111100
  27. 00011000
  28. 00011000
  29. 00011000
  30. 00000000
  31. 00011000
  32. 00011000
  33. 00000000
  34. 00000000
  35. 00000000
  36. 00000000
  37. //显然,在代码实现中,每个字符就是8*16像素的二进制矩阵,我们将“1”的绘制前景色,“0”的绘制背景色,就能显示字符
复制代码

        (3)显然,在代码实现中,每个字符就是8*16像素的二进制矩阵,我们将“1”的绘制前景色,“0”的绘制背景色,就能显示字符

        现在给出字符8*16二进制矩阵获取代码:
  1. //addr为字符的地址信息
  2.         uint8_t buffer[16][8]={0};
  3.         for(uint8_t i=0; i<16; i++)
  4.         {
  5.                 uint16_t buf=ASCII_8x16[(addr*16)+i-512];
  6.                 printf("0X%02X ",buf);
  7.                 for(uint8_t j=0;j<8;j++){
  8.                         printf("%d ",(0x01&(buf>>j))>0?0x01:0x00);//注意这里低字节开始取值,与前面分析的就刚好反至了,但原理是一样的
  9.                         buffer[8*(i/8)+j][i%8]=(0x01&(buf>>j))>0?1:0;
  10.                 }
  11.                 printf("\r\n");
  12.         }
  13.         for(uint8_t i=0; i<16; i++)
  14.         {
  15.                 for(uint8_t j=0;j<8;j++){
  16.                         printf("%d",buffer[i][j]);
  17.                 }
  18.                 printf("\r\n");
  19.         }
复制代码

        (4)测试“!”输出如下,妥妥的一个!,需要注意的是,下图第一部分的打印输出,由于我们打印时从低字节位开始取数,和前面分析(步骤(1)是从高位取数)的呈现出反至效果:

881370147d4d419095351e2f7926aea1.png

【3】字符串olde输出
        知道一个字符如何在屏幕输出,那么一个字符串输出就是逐个8*16的像素格子渲染输出,具体代码设置如下,OLED_printf实现在屏幕指定位置开始,打印输出字符串,字符串如果过大,将更换到下一行(即y方向下移16像素,屏幕左上角位置为0,0,向右为X轴方向递增,向下位Y轴方向递增),因此该函数会将输入的字符串进行切分成多行。OLED_DISPLAY_8x16函数用于在oled屏幕上输出一个字符的8*16像素绘制。OLED_printf_US测试通过调研OLED_DISPLAY_8x16实现一行字符的输出。
  1. //显示英文与数字8*16的ASCII码
  2. void OLED_DISPLAY_8x16(uint8_t x, uint8_t y, uint16_t w){ //要显示汉字的编号
  3. //        printf("x=%d,y=%d,w=0X%04X w*16-512=%d\r\n",x,y,w,w*16-512);
  4.         uint16_t color = 0;
  5.         uint16_t textData[16][8]={0};
  6. //        uint8_t buffer[16][8]={0};
  7.         for(uint8_t i=0; i<16; i++)
  8.         {
  9.                 uint16_t buf=ASCII_8x16[(w*16)+i-512];
  10. //                printf("0X%02X ",buf);
  11.                 for(uint8_t j=0;j<8;j++){
  12. //                        printf("%d ",(0x01&(buf>>j))>0?0x01:0x00);
  13. //                        buffer[8*(i/8)+j][i%8]=(0x01&(buf>>j))>0?1:0;
  14.                         color = (0x01&(buf>>j))>0?LCD_DISP_BLACK:LCD_DISP_BLUE;
  15.                         textData[8*(i/8)+j][i%8] = color;
  16. //                        OLED_WritePixel(x+i%8,y+8*(i/8)+j,color);//单像素渲染
  17.                 }
  18. //                printf("\r\n");
  19.         }
  20.         for(uint8_t i=0; i<16; i++)
  21.         {
  22.                 OLED_WriteLine(x,y+i,textData[i],8);//列像素渲染
  23. //                for(uint8_t j=0;j<8;j++){
  24. //                        printf("%d",buffer[i][j]);
  25. //                }
  26. //                printf("\r\n");
  27.         }
  28. }

  29. //用于OLED_printf函数专用的显示程序
  30. void OLED_printf_US(uint8_t xpos,uint8_t ypos,uint8_t *str,uint8_t i){
  31.         uint8_t r=0;
  32.         while(i != r){//i是长度值,当显示到i之后退出
  33.                 OLED_DISPLAY_8x16(xpos+r*8,ypos,*str++);//显示英文与数字8*16的ASCII码
  34.                 r++;
  35.     }
  36. }
  37. //OLED专用的printf函数
  38. //调用方法:OLED_printf(0,0,"123");
  39. //注意若xpos或ypos过大,并内容较多时,会出现溢出边界
  40. #define line_size 29
  41. #define row_size 16
  42. void OLED_printf (uint8_t xpos,uint8_t ypos,char *fmt, ...)
  43. {
  44.     char buff[line_size];  //用于存放转换后的数据 [长度],限定30字符长度,每个字符8像素宽度,屏幕宽240
  45.     uint16_t size=0;
  46.     uint16_t row = 1+strlen(fmt)/line_size;//暂时没考虑自带换行符号情况
  47. //    printf("row=%d\r\n",row);
  48.     for(uint16_t i=0;i<row;i++){
  49.         va_list arg_ptr;
  50.         va_start(arg_ptr,fmt);
  51.         vsnprintf(buff, line_size,fmt+i*line_size,arg_ptr);//数据转换
  52.         size=strlen(buff);                                        //得出数据长度
  53.         if(strlen(buff)>line_size)size=line_size;                        //如果长度大于最大值,则长度等于最大值(多出部分忽略)
  54.         OLED_printf_US(xpos,ypos+i*row_size,(uint8_t *)buff,size);//最终调用OLED专用的printf函数来显示
  55.         va_end(arg_ptr);
  56.     }
  57. }
复制代码

【4】SPI的直接输出和DMA输出区别实现
        设置两个清屏函数BSP_LCD_Clear和BSP_LCD_Clear_DMA,一个采用HAL_SPI_Transmit写入数据显示,前面所述都是这种方式(通过调用LcdWriteData、LcdWriteDataMultiple,这个函数采用HAL_SPI_Transmit实现的),一个调用HAL_SPI_Transmit_DMA写入数据显示。

        BSP_LCD_Clear实现就是调用LcdWriteDataMultiple绘制240行的线,BSP_LCD_Clear_DMA实现就是分为两个半屏绘制(HAL_SPI_Transmit_DMA的接收数据组大小类型是uint16_t,最大支持0xfff,65535)。
  1. static void LCD_Address_Set(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2)
  2. {
  3.     /* 指定X方向操作区域 */
  4.         LcdWriteReg(0x2a);
  5.         LcdWriteData(x1 >> 8);
  6.         LcdWriteData(x1);
  7.         LcdWriteData(x2 >> 8);
  8.         LcdWriteData(x2);

  9.     /* 指定Y方向操作区域 */
  10.         LcdWriteReg(0x2b);
  11.     LcdWriteData(y1 >> 8);
  12.     LcdWriteData(y1);
  13.     LcdWriteData(y2 >> 8);
  14.     LcdWriteData(y2);

  15.     /* 发送该命令,LCD开始等待接收显存数据 */
  16.     LcdWriteReg(0x2C);
  17. }
  18. //指定位置,绘制一行像素直到屏幕右侧
  19. void OLED_SetCursor(uint16_t Xpos, uint16_t Ypos)
  20. {
  21.         LCD_Address_Set(Xpos,Ypos,WIDTH-1,Ypos);
  22. }

  23. void BSP_LCD_Clear(uint16_t Color)
  24. {
  25.         uint8_t black_gui[480] = {0};
  26.         memset(black_gui, Color, sizeof(black_gui));

  27.         for (uint32_t counter = 0; counter < 240; counter++)
  28.         {
  29.                 /* Set Cursor */
  30.                 OLED_SetCursor(0, counter);
  31.                 /* Prepare to write to LCD RAM */
  32.                 OLED_WriteReg(0x2C, (uint8_t*)NULL, 0);
  33.                 /* RAM write data command */
  34.                 LcdWriteDataMultiple(black_gui, 480);
  35.         }
  36. }

  37. extern volatile uint8_t one_frame_done;
  38. void BSP_LCD_Clear_DMA(uint16_t Color)
  39. {
  40.         uint8_t black_gui_DMA[WIDTH*HEIGHT*2] = {0X00};
  41.         for(uint32_t i=0; i<WIDTH*HEIGHT; i++)
  42.         {
  43.                 black_gui_DMA[2*i]=Color>>8;
  44.                 black_gui_DMA[2*i+1] = Color;
  45.         }
  46.         printf("0X%02x%02x\r\n",black_gui_DMA[0],black_gui_DMA[1]);
  47.         //需要分两次写入HAL_SPI_Transmit_DMA写入缓存大小uint16_t(0xfff,65535)
  48.         one_frame_done = 0;
  49.     /* 指定显存操作地址为全屏*/
  50.     LCD_Address_Set(0, 0, WIDTH - 1, HEIGHT/2 - 1);
  51.     Data_Cmd_State(1);/* 指定接下来的数据为数据 */
  52.     /*DMA 写前半屏*/
  53.     HAL_SPI_Transmit_DMA(&hspi1,black_gui_DMA, WIDTH*HEIGHT);
  54.     while(!one_frame_done){/*release cpu and doing something else*/}
  55.         one_frame_done = 0;
  56.     /* 指定显存操作地址为全屏*/
  57.     LCD_Address_Set(0, HEIGHT/2, WIDTH - 1, HEIGHT - 1);
  58.     Data_Cmd_State(1);/* 指定接下来的数据为数据 */
  59.     /*DMA 写后半屏*/
  60.     HAL_SPI_Transmit_DMA(&hspi1,black_gui_DMA+WIDTH*HEIGHT, WIDTH*HEIGHT);
  61.     while(!one_frame_done){/*release cpu and doing something else*/}
  62. }
复制代码

        前文3.3小节,已经开启了SPI的外部中断功能,则SPI的回调函数会被调用。one_frame_done是一个全局变量,在spi.c中定义,需要在spi.c加上HAL_SPI_TxCpltCallback的函数,用来替换stm32l4xx_hal_spi.c文件的spi中断回调实现:
  1. //spi.c末加上spi的中断回调实现
  2. /* USER CODE BEGIN 1 */
  3. volatile uint8_t one_frame_done;
  4. void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
  5. {
  6.         one_frame_done = 1;
  7. }
  8. /* USER CODE END 1 */

  9. //用来替换调stm32l4xx_hal_spi.c的弱函数
  10. __weak void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
  11. {
  12.   /* Prevent unused argument(s) compilation warning */
  13.   UNUSED(hspi);

  14.   /* NOTE : This function should not be modified, when the callback is needed,
  15.             the HAL_SPI_TxCpltCallback should be implemented in the user file
  16.    */
  17. }
复制代码

六、程序编译及测试
        在main.c中加入按键功能,一个按键直接写入方式清屏(黑屏),一个按键DMA写入方式清屏(蓝屏幕),一个按键实现屏幕输出一段文字,另外通过串口发送字符串,实现在屏幕输出显示。
  1. /* USER CODE BEGIN WHILE */
  2.   while (1)
  3.   {
  4.           if(HLPUSART_RX_STA&0xC000){//溢出或换行,重新开始
  5.                   OLED_printf(10,10,"%.*s",HLPUSART_RX_STA&0X0FFF, HLPUSART_RX_BUF);
  6.                   HLPUSART_RX_STA=0;//接收错误,重新开始
  7.                   HAL_Delay(100);//等待
  8.           }
  9.           if(KEY_0())
  10.           {
  11.                   OLED_printf(10,10,"hello world to stm32!I am an embedded enthusiast.");
  12.                   OLED_printf(10,48,"  STM32CubeIDE is an advanced C/C++ development platform "
  13.                                   "with peripheral configuration, code generation, code compilation, "
  14.                                   "and debug features for STM32 micro controllers and microprocessors.");
  15. //                  OLED_printf(10,10,"!");
  16.           }
  17.           if(KEY_1())
  18.           {
  19.                   BSP_LCD_Clear(0xF800);
  20.                   printf("OLED_Clear\r\n");
  21.           }
  22.           if(KEY_2())
  23.           {
  24.                   BSP_LCD_Clear_DMA(LCD_DISP_BLUE);
  25.                   printf("OLED_Clear_DMA\r\n");
  26.           }
  27.         Toggle_led0();
  28.     /* USER CODE END WHILE */
复制代码

        编译完成后测试效果如下:

        1)按键key1清屏,发送字符串

2e9a5bb3b7d045989cff15c0cb8bc46d.png

b568c269e9924186bbdc42a1f67fb951.png


        2)按键key0,输出一段文字

8ac981ffb14548348592079d236efe9b.png


七、附件
        oled.h
  1. #ifndef _OLED_H_
  2. #define _OLED_H_
  3. /*
  4. * for st7789 oled 模组
  5. */
  6. #define WIDTH                240
  7. #define HEIGHT                240
  8. #define BPP                16

  9. /* Init script function */
  10. struct OLED_function {
  11.   uint8_t cmd;
  12.   uint16_t data;
  13. };

  14. /* Init script commands */
  15. enum OLED_cmd {
  16.   OLED_START,
  17.   OLED_END,
  18.   OLED_CMD,
  19.   OLED_DATA,
  20.   OLED_DELAY
  21. };

  22. /************** 颜色(RGB 5,6,5) **************/
  23. #define LCD_DISP_RED                    0xF800       //先高字节,后低字节
  24. #define LCD_DISP_GREEN                  0x07E0
  25. #define LCD_DISP_BLUE                   0x001F
  26. #define LCD_DISP_WRITE                  0xFFFF
  27. #define LCD_DISP_BLACK                  0x0000
  28. #define LCD_DISP_GRAY                   0xEF5D
  29. #define LCD_DISP_GRAY75                 0x39E7
  30. #define LCD_DISP_GRAY50                 0x7BEF
  31. #define LCD_DISP_GRAY25                 0xADB5

  32. /* oled Commands */
  33. #define OLED_CASET        0x2A
  34. #define OLED_RASET        0x2B
  35. #define OLED_RAMWR        0x2C
  36. #define OLED_RAMRD        0x2E

  37. //对该位写1或0
  38. #define Data_Cmd_State(__D_C_State__)        HAL_GPIO_WritePin(LCD_DCX_GPIO_Port, LCD_DCX_Pin, (GPIO_PinState)(__D_C_State__))
  39. #define OLED_RST_State(__RST_State__)        HAL_GPIO_WritePin(LCD_RST_GPIO_Port, LCD_RST_Pin, (GPIO_PinState)(__RST_State__))
  40. #define LCD_PWR_State(__PWR_State__)        HAL_GPIO_WritePin(LCD_PWR_GPIO_Port, LCD_PWR_Pin, (GPIO_PinState)(__PWR_State__))

  41. int OLED_init();
  42. void LcdWriteReg(uint8_t Data);
  43. void LcdWriteData(uint8_t Data);
  44. void LcdWriteDataMultiple(uint8_t * pData, uint32_t NumItems);

  45. void OLED_WritePixel(uint16_t Xpos, uint16_t Ypos, uint16_t RGBCode);
  46. void OLED_WriteLine(uint16_t Xpos, uint16_t Ypos, uint16_t *RGBCode, uint16_t pointNum);

  47. void BSP_LCD_Clear(uint16_t Color);
  48. void BSP_LCD_Clear_DMA(uint16_t Color);
  49. void OLED_printf (uint8_t xpos,uint8_t ypos,char *fmt, ...);

  50. #endif /* __oled_H */
复制代码

oled.c
  1. #include "stm32l4xx_hal.h"
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <stdarg.h>
  6. #include "main.h"
  7. #include "ASCII.h"
  8. #include "oled.h"

  9. extern SPI_HandleTypeDef hspi1;
  10. //初始化命令集
  11. static struct OLED_function OLED_cfg_script[] = {
  12.   {OLED_START, OLED_START},
  13.   {OLED_CMD, 0x11},
  14.   {OLED_DELAY, 120},
  15.   {OLED_CMD, 0x36},
  16.   {OLED_DATA, 0x00},
  17.   {OLED_CMD, 0x3a},
  18.   {OLED_DATA, 0x65},
  19.   {OLED_CMD, 0xb2},
  20.   {OLED_DATA, 0x0c},
  21.   {OLED_DATA, 0x0c},
  22.   {OLED_DATA, 0x00},
  23.   {OLED_DATA, 0x33},
  24.   {OLED_DATA, 0x33},
  25.   {OLED_CMD, 0xb7},
  26.   {OLED_DATA, 0x72},
  27.   {OLED_CMD, 0xbb},
  28.   {OLED_DATA, 0x3d},
  29.   {OLED_CMD, 0xc0},
  30.   {OLED_DATA, 0x2c},
  31.   {OLED_CMD, 0xc2},
  32.   {OLED_DATA, 0x01},
  33.   {OLED_CMD, 0xc3},
  34.   {OLED_DATA, 0x19},
  35.   {OLED_CMD, 0xc4},
  36.   {OLED_DATA, 0x20},
  37.   {OLED_CMD, 0xc6},
  38.   {OLED_DATA, 0x0f},
  39.   {OLED_CMD, 0xd0},
  40.   {OLED_DATA, 0xa4},
  41.   {OLED_DATA, 0xa1},
  42.   {OLED_CMD, 0xe0},
  43.   {OLED_DATA, 0x70},
  44.   {OLED_DATA, 0x04},
  45.   {OLED_DATA, 0x08},
  46.   {OLED_DATA, 0x09},
  47.   {OLED_DATA, 0x09},
  48.   {OLED_DATA, 0x05},
  49.   {OLED_DATA, 0x2a},
  50.   {OLED_DATA, 0x33},
  51.   {OLED_DATA, 0x41},
  52.   {OLED_DATA, 0x07},
  53.   {OLED_DATA, 0x13},
  54.   {OLED_DATA, 0x13},
  55.   {OLED_DATA, 0x29},
  56.   {OLED_DATA, 0x2f},
  57.   {OLED_CMD, 0xe1},
  58.   {OLED_DATA, 0x70},
  59.   {OLED_DATA, 0x03},
  60.   {OLED_DATA, 0x09},
  61.   {OLED_DATA, 0x0a},
  62.   {OLED_DATA, 0x09},
  63.   {OLED_DATA, 0x06},
  64.   {OLED_DATA, 0x2b},
  65.   {OLED_DATA, 0x34},
  66.   {OLED_DATA, 0x41},
  67.   {OLED_DATA, 0x07},
  68.   {OLED_DATA, 0x12},
  69.   {OLED_DATA, 0x14},
  70.   {OLED_DATA, 0x28},
  71.   {OLED_DATA, 0x2e},
  72.   {OLED_CMD, 0x21},
  73.   {OLED_CMD, 0x29},
  74.   {OLED_CMD, 0x2a},
  75.   {OLED_DATA, 0x00},
  76.   {OLED_DATA, 0x00},
  77.   {OLED_DATA, 0x00},
  78.   {OLED_DATA, 0xef},
  79.   {OLED_CMD, 0x2b},
  80.   {OLED_DATA, 0x00},
  81.   {OLED_DATA, 0x00},
  82.   {OLED_DATA, 0x00},
  83.   {OLED_DATA, 0xef},
  84.   {OLED_CMD, 0x2c},
  85.   {OLED_END, OLED_END},
  86. };

  87. static void OLED_run_cfg_script()
  88. {
  89.           uint8_t data[2] = {0};
  90.           int i = 0;
  91.           int end_script = 0;

  92.           do {
  93.             switch (OLED_cfg_script[i].cmd) {
  94.             case OLED_START:
  95.               break;
  96.             case OLED_CMD:
  97.               data[0] = OLED_cfg_script[i].data & 0xff;
  98.               LcdWriteReg(data[0]);
  99.               break;
  100.             case OLED_DATA:
  101.               data[0] = OLED_cfg_script[i].data & 0xff;
  102.               LcdWriteData(data[0]);
  103.               break;
  104.             case OLED_DELAY:
  105.               HAL_Delay(OLED_cfg_script[i].data);
  106.               break;
  107.             case OLED_END:
  108.               end_script = 1;
  109.             }
  110.             i++;
  111.           } while (!end_script);
  112. }

  113. static void OLED_reset()
  114. {
  115.           OLED_RST_State(0);
  116.           HAL_Delay(200);
  117.           OLED_RST_State(1);
  118.           HAL_Delay(150);
  119. }

  120. #define LCD_MAX_MEM16_BLOCK             (1 << 6)
  121. #define LCD_PIXEL_PER_BLOCK             (LCD_MAX_MEM16_BLOCK >> 1)

  122. static void spec_send_fb(uint16_t color, uint16_t pixel_num)
  123. {
  124.           uint16_t real_mem[LCD_MAX_MEM16_BLOCK] = {0};

  125.           for (uint16_t i = 0; i < LCD_MAX_MEM16_BLOCK; ++i) {
  126.                   real_mem[i] = color;
  127.           }
  128. //          HAL_GPIO_WritePin(LCD_DCX_GPIO_Port, LCD_DCX_Pin, GPIO_PIN_SET);
  129.           Data_Cmd_State(GPIO_PIN_SET);
  130.           if (pixel_num <= LCD_MAX_MEM16_BLOCK) {
  131.                   LcdWriteDataMultiple((uint8_t*)real_mem, pixel_num << 1);
  132.           } else {
  133.                   uint16_t count = pixel_num / LCD_MAX_MEM16_BLOCK;
  134.                   uint16_t remain = pixel_num % LCD_MAX_MEM16_BLOCK;
  135.                   for (uint16_t i = 0; i < count; ++i) {
  136.                           LcdWriteDataMultiple((uint8_t*)real_mem, LCD_MAX_MEM16_BLOCK << 1);
  137.                   }
  138.                   LcdWriteDataMultiple((uint8_t*)real_mem, remain << 1);
  139.           }
  140. }

  141. static void OLED_display_picture(void)
  142. {
  143.   LcdWriteReg(OLED_RAMWR);
  144.   spec_send_fb(0x0, WIDTH * HEIGHT / 4);
  145.   spec_send_fb(0x1111, WIDTH * HEIGHT / 4);
  146.   spec_send_fb(0x7777, WIDTH * HEIGHT / 4);
  147.   spec_send_fb(0xeeee, WIDTH * HEIGHT / 4);
  148. }


  149. int OLED_init()
  150. {
  151.           LCD_PWR_State(0);//回显关闭
  152.           OLED_reset();
  153.           OLED_run_cfg_script();
  154.           LCD_PWR_State(1);//回显开启
  155.           OLED_display_picture();

  156.           return HAL_OK;
  157. }

  158. void OLED_WriteReg(uint8_t Command, uint8_t *Parameters, uint8_t NbParameters)
  159. {
  160.           /* Send command */
  161.           LcdWriteReg(Command);

  162.           /* Send command's parameters if any */
  163.           for (uint8_t i=0; i<NbParameters; i++)
  164.           {
  165.             LcdWriteData(Parameters[i]);
  166.           }
  167. }

  168. static void LCD_Address_Set(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2)
  169. {
  170.     /* 指定X方向操作区域 */
  171.         LcdWriteReg(0x2a);
  172.         LcdWriteData(x1 >> 8);
  173.         LcdWriteData(x1);
  174.         LcdWriteData(x2 >> 8);
  175.         LcdWriteData(x2);

  176.     /* 指定Y方向操作区域 */
  177.         LcdWriteReg(0x2b);
  178.     LcdWriteData(y1 >> 8);
  179.     LcdWriteData(y1);
  180.     LcdWriteData(y2 >> 8);
  181.     LcdWriteData(y2);

  182.     /* 发送该命令,LCD开始等待接收显存数据 */
  183.     LcdWriteReg(0x2C);
  184. }

  185. void OLED_SetCursor(uint16_t Xpos, uint16_t Ypos)
  186. {
  187.         LCD_Address_Set(Xpos,Ypos,WIDTH-1,Ypos);
  188. }

  189. void BSP_LCD_Clear(uint16_t Color)
  190. {
  191.         uint8_t black_gui[480] = {0};
  192.         memset(black_gui, Color, sizeof(black_gui));

  193.         for (uint32_t counter = 0; counter < 240; counter++)
  194.         {
  195.                 /* Set Cursor */
  196.                 OLED_SetCursor(0, counter);
  197.                 /* Prepare to write to LCD RAM */
  198.                 OLED_WriteReg(0x2C, (uint8_t*)NULL, 0);
  199.                 /* RAM write data command */
  200.                 LcdWriteDataMultiple(black_gui, 480);
  201.         }
  202. }

  203. extern volatile uint8_t one_frame_done;
  204. void BSP_LCD_Clear_DMA(uint16_t Color)
  205. {
  206.         uint8_t black_gui_DMA[WIDTH*HEIGHT*2] = {0X00};
  207.         for(uint32_t i=0; i<WIDTH*HEIGHT; i++)
  208.         {
  209.                 black_gui_DMA[2*i]=Color>>8;
  210.                 black_gui_DMA[2*i+1] = Color;
  211.         }
  212.         printf("0X%02x%02x\r\n",black_gui_DMA[0],black_gui_DMA[1]);
  213.         //需要分两次写入HAL_SPI_Transmit_DMA写入缓存大小uint16_t(0xfff,65535)
  214.         one_frame_done = 0;
  215.     /* 指定显存操作地址为全屏*/
  216.     LCD_Address_Set(0, 0, WIDTH - 1, HEIGHT/2 - 1);
  217.     Data_Cmd_State(1);/* 指定接下来的数据为数据 */
  218.     /*DMA 写前半屏*/
  219.     HAL_SPI_Transmit_DMA(&hspi1,black_gui_DMA, WIDTH*HEIGHT);
  220.     while(!one_frame_done){/*release cpu and doing something else*/}
  221.         one_frame_done = 0;
  222.     /* 指定显存操作地址为全屏*/
  223.     LCD_Address_Set(0, HEIGHT/2, WIDTH - 1, HEIGHT - 1);
  224.     Data_Cmd_State(1);/* 指定接下来的数据为数据 */
  225.     /*DMA 写后半屏*/
  226.     HAL_SPI_Transmit_DMA(&hspi1,black_gui_DMA+WIDTH*HEIGHT, WIDTH*HEIGHT);
  227.     while(!one_frame_done){/*release cpu and doing something else*/}
  228. }

  229. //显示英文与数字8*16的ASCII码
  230. void OLED_DISPLAY_8x16(uint8_t x, uint8_t y, uint16_t w){ //要显示汉字的编号
  231. //        printf("x=%d,y=%d,w=0X%04X w*16-512=%d\r\n",x,y,w,w*16-512);
  232.         uint16_t color = 0;
  233.         uint16_t textData[16][8]={0};
  234. //        uint8_t buffer[16][8]={0};
  235.         for(uint8_t i=0; i<16; i++)
  236.         {
  237.                 uint16_t buf=ASCII_8x16[(w*16)+i-512];
  238. //                printf("0X%02X ",buf);
  239.                 for(uint8_t j=0;j<8;j++){
  240. //                        printf("%d ",(0x01&(buf>>j))>0?0x01:0x00);
  241. //                        buffer[8*(i/8)+j][i%8]=(0x01&(buf>>j))>0?1:0;
  242.                         color = (0x01&(buf>>j))>0?LCD_DISP_BLACK:LCD_DISP_BLUE;
  243.                         textData[8*(i/8)+j][i%8] = color;
  244. //                        OLED_WritePixel(x+i%8,y+8*(i/8)+j,color);//单像素渲染
  245.                 }
  246. //                printf("\r\n");
  247.         }
  248.         for(uint8_t i=0; i<16; i++)
  249.         {
  250.                 OLED_WriteLine(x,y+i,textData[i],8);//列像素渲染
  251. //                for(uint8_t j=0;j<8;j++){
  252. //                        printf("%d",buffer[i][j]);
  253. //                }
  254. //                printf("\r\n");
  255.         }
  256. }

  257. //用于OLED_printf函数专用的显示程序
  258. void OLED_printf_US(uint8_t xpos,uint8_t ypos,uint8_t *str,uint8_t i){
  259.         uint8_t r=0;
  260.         while(i != r){//i是长度值,当显示到i之后退出
  261.                 OLED_DISPLAY_8x16(xpos+r*8,ypos,*str++);//显示英文与数字8*16的ASCII码
  262.                 r++;
  263.     }
  264. }
  265. //OLED专用的printf函数
  266. //调用方法:OLED_printf(0,0,"123");
  267. //注意若xpos或ypos过大,并内容较多时,会出现溢出边界
  268. #define line_size 29
  269. #define row_size 16
  270. void OLED_printf (uint8_t xpos,uint8_t ypos,char *fmt, ...)
  271. {
  272.     char buff[line_size];  //用于存放转换后的数据 [长度],限定30字符长度,每个字符8像素宽度,屏幕宽240
  273.     uint16_t size=0;
  274.     uint16_t row = 1+strlen(fmt)/line_size;//暂时没考虑自带换行符号情况
  275. //    printf("row=%d\r\n",row);
  276.     for(uint16_t i=0;i<row;i++){
  277.         va_list arg_ptr;
  278.         va_start(arg_ptr,fmt);
  279.         vsnprintf(buff, line_size,fmt+i*line_size,arg_ptr);//数据转换
  280.         size=strlen(buff);                                        //得出数据长度
  281.         if(strlen(buff)>line_size)size=line_size;                        //如果长度大于最大值,则长度等于最大值(多出部分忽略)
  282.         OLED_printf_US(xpos,ypos+i*row_size,(uint8_t *)buff,size);//最终调用OLED专用的printf函数来显示
  283.         va_end(arg_ptr);
  284.     }
  285. }

  286. void OLED_WritePixel(uint16_t Xpos, uint16_t Ypos, uint16_t data)
  287. {
  288.           uint8_t dataB = 0;

  289.           /* Set Cursor */
  290.           OLED_SetCursor(Xpos, Ypos);

  291.           /* Prepare to write to LCD RAM */
  292.           OLED_WriteReg(0x2C, (uint8_t*)NULL, 0);   /* RAM write data command */

  293.           /* Write RAM data */
  294.           dataB = (uint8_t)(data >> 8);
  295.           LcdWriteData(dataB);
  296.           dataB = (uint8_t)data;
  297.           LcdWriteData(dataB);
  298. }

  299. uint8_t endian_buffer[480];

  300. void OLED_WriteLine(uint16_t Xpos, uint16_t Ypos, uint16_t *RGBCode, uint16_t pointNum)
  301. {
  302.           /* Set Cursor */
  303.           OLED_SetCursor(Xpos, Ypos);

  304.           /* Prepare to write to LCD RAM */
  305.           OLED_WriteReg(0x2C, (uint8_t*)NULL, 0);   /* RAM write data command */

  306.           for (uint16_t i = 0; i < pointNum; i++) {
  307.             endian_buffer[2*i] = (uint8_t)(RGBCode[i] >> 8);
  308.             endian_buffer[2*i + 1] = (uint8_t)RGBCode[i];
  309.           }

  310.           /* Write RAM data */
  311.           LcdWriteDataMultiple(endian_buffer, pointNum*2);
  312. }

  313. /********************************************************************
  314. *
  315. *   LcdWriteReg
  316. *
  317. *         Function description:
  318. *   Sets display register
  319. */
  320. void LcdWriteReg(uint8_t Data)
  321. {
  322.           Data_Cmd_State(0);
  323.           HAL_SPI_Transmit(&hspi1, &Data, 1, 10);
  324. }

  325. /********************************************************************
  326. *
  327. *          LcdWriteData
  328. *
  329. *         Function description:
  330. *   Writes a value to a display register
  331. */
  332. void LcdWriteData(uint8_t Data)
  333. {
  334.           Data_Cmd_State(1);
  335.           HAL_SPI_Transmit(&hspi1, &Data, 1, 10);
  336. }

  337. /********************************************************************
  338. *
  339. *        LcdWriteDataMultiple
  340. *
  341. *         Function description:
  342. *   Writes multiple values to a display register.
  343. */
  344. void LcdWriteDataMultiple(uint8_t * pData, uint32_t NumItems)
  345. {
  346.           Data_Cmd_State(1);
  347.           HAL_SPI_Transmit(&hspi1, pData, NumItems, 10);
  348. }
复制代码

ASCII.h源码前文已给出,mian.c部分源码:
  1. /* USER CODE END Header */
  2. /* Includes ------------------------------------------------------------------*/
  3. #include "main.h"
  4. #include "dcmi.h"
  5. #include "dma.h"
  6. #include "i2c.h"
  7. #include "usart.h"
  8. #include "spi.h"
  9. #include "gpio.h"

  10. /* Private includes ----------------------------------------------------------*/
  11. /* USER CODE BEGIN Includes */
  12. #include "../../ICore/key/key.h"
  13. #include "../../ICore/led/led.h"
  14. #include "../../ICore/print/print.h"
  15. #include "../../ICore/usart/usart.h"
  16. #include "../../ICore/oled/oled.h"
  17. /* USER CODE END Includes */

  18. /* Private typedef -----------------------------------------------------------*/
  19. /* USER CODE BEGIN PTD */

  20. /* USER CODE END PTD */

  21. /* Private define ------------------------------------------------------------*/
  22. /* USER CODE BEGIN PD */
  23. /* USER CODE END PD */

  24. /* Private macro -------------------------------------------------------------*/
  25. /* USER CODE BEGIN PM */

  26. /* USER CODE END PM */

  27. /* Private variables ---------------------------------------------------------*/

  28. /* USER CODE BEGIN PV */

  29. /* USER CODE END PV */

  30. /* Private function prototypes -----------------------------------------------*/
  31. void SystemClock_Config(void);
  32. /* USER CODE BEGIN PFP */

  33. /* USER CODE END PFP */

  34. /* Private user code ---------------------------------------------------------*/
  35. /* USER CODE BEGIN 0 */
  36. //volatile uint8_t data1[LCD_RAM_SIZE];
  37. //volatile uint8_t data2[LCD_RAM_SIZE];
  38. //extern volatile uint8_t one_frame_done;
  39. /* USER CODE END 0 */

  40. /**
  41.   * @brief  The application entry point.
  42.   * @retval int
  43.   */
  44. int main(void)
  45. {
  46.   /* USER CODE BEGIN 1 */

  47.   /* USER CODE END 1 */

  48.   /* MCU Configuration--------------------------------------------------------*/

  49.   /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  50.   HAL_Init();

  51.   /* USER CODE BEGIN Init */

  52.   /* USER CODE END Init */

  53.   /* Configure the system clock */
  54.   SystemClock_Config();

  55.   /* USER CODE BEGIN SysInit */

  56.   /* USER CODE END SysInit */

  57.   /* Initialize all configured peripherals */
  58.   MX_GPIO_Init();
  59.   MX_DMA_Init();
  60.   MX_LPUART1_UART_Init();
  61.   MX_SPI1_Init();
  62.   /* USER CODE BEGIN 2 */
  63.   ResetPrintInit(&hlpuart1);
  64.   HAL_UART_Receive_IT(&hlpuart1,(uint8_t *)&HLPUSART_NewData, 1); //再开启接收中断
  65.   HLPUSART_RX_STA = 0;
  66.   OLED_init();
  67.   //
  68.   set_led0_val(0);
  69.   set_led1_val(get_key0_val());
  70.   /* USER CODE END 2 */

  71.   /* Infinite loop */
  72.   /* USER CODE BEGIN WHILE */
  73.   while (1)
  74.   {
  75.           if(HLPUSART_RX_STA&0xC000){//溢出或换行,重新开始
  76.                   OLED_printf(10,10,"%.*s",HLPUSART_RX_STA&0X0FFF, HLPUSART_RX_BUF);
  77.                   HLPUSART_RX_STA=0;//接收错误,重新开始
  78.                   HAL_Delay(100);//等待
  79.           }
  80.           if(KEY_0())
  81.           {
  82.                   OLED_printf(10,10,"hello world to stm32!I am an embedded enthusiast.");
  83.                   OLED_printf(10,48,"  STM32CubeIDE is an advanced C/C++ development platform "
  84.                                   "with peripheral configuration, code generation, code compilation, "
  85.                                   "and debug features for STM32 micro controllers and microprocessors.");
  86. //                  OLED_printf(10,10,"!");
  87.           }
  88.           if(KEY_1())
  89.           {
  90.                   BSP_LCD_Clear(0xF800);
  91.                   printf("OLED_Clear\r\n");
  92.           }
  93.           if(KEY_2())
  94.           {
  95.                   BSP_LCD_Clear_DMA(LCD_DISP_BLUE);
  96.                   printf("OLED_Clear_DMA\r\n");
  97.           }
  98.         Toggle_led0();
  99.     /* USER CODE END WHILE */

  100.     /* USER CODE BEGIN 3 */
  101.   }
  102.   /* USER CODE END 3 */
  103. }
复制代码

————————————————
版权声明:py_free-物联智能
如有侵权请联系删除





收藏 评论0 发布时间:2023-4-7 15:18

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版