[STM32U3] 【STM32U385RG 测评】+ OLED屏显示驱动与RTC时钟

[复制链接]
 楼主| jinglixixi 发表于 2025-7-15 20:03 | 显示全部楼层 |阅读模式
本帖最后由 jinglixixi 于 2025-7-15 21:20 编辑

前面介绍了以软件模拟的方式来驱动OLED屏,有了其成功的基础再来尝试硬件的驱动方式就方便了许多,因为硬件驱动的主要工作就是配置I2C的初始化函数及变更I2C发送字节数据的发送,其他的基本无需进行调整。


1. OLED显示屏驱动
为了驱动OLED显示屏,这里使用的接口I2C2,相应的引脚连接关系为:

OLED_SCL -----I2C2_SCL----- PB13     
OLED_SDA------I2C2_SDA------PB14


I2C2的初始化函数为:
  1. void MX_I2C2_Init(void)
  2. {
  3.   hi2c2.Instance = I2C2;
  4.   hi2c2.Init.Timing = 0x009032AE;
  5.   hi2c2.Init.OwnAddress1 = 0;
  6.   hi2c2.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
  7.   hi2c2.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
  8.   hi2c2.Init.OwnAddress2 = 0;
  9.   hi2c2.Init.OwnAddress2Masks = I2C_OA2_NOMASK;
  10.   hi2c2.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
  11.   hi2c2.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
  12.   if (HAL_I2C_Init(&hi2c2) != HAL_OK)
  13.   {
  14.     Error_Handler();
  15.   }

  16.   if (HAL_I2CEx_ConfigAnalogFilter(&hi2c2, I2C_ANALOGFILTER_ENABLE) != HAL_OK)
  17.   {
  18.     Error_Handler();
  19.   }

  20.   if (HAL_I2CEx_ConfigDigitalFilter(&hi2c2, 0) != HAL_OK)
  21.   {
  22.     Error_Handler();
  23.   }
  24. }

实现I2C发送字节数据的函数为:
  1. #define OLED_ADDRESS   0x78
  2. void I2C_WriteByte(uint8_t addr, uint8_t dat)
  3. {
  4.         uint8_t temp[2];
  5.         temp[0] = dat;
  6.         temp[1] = dat;
  7.         HAL_I2C_Mem_Write(&hi2c2,OLED_ADDRESS,addr,I2C_MEMADD_SIZE_8BIT,temp,1,10);
  8. }

实现指令发送的函数为:
  1. void WriteCmd(unsigned char I2C_Command)
  2. {
  3.     I2C_WriteByte(0x00, I2C_Command);
  4. }

对所用显示屏的初始化函数为:
  1. void OLED_Init(void)
  2. {
  3.         HAL_Delay(100);
  4.         WriteCmd(0xAE);  //display off
  5.         WriteCmd(0x40);
  6.         WriteCmd(0xb0);        //Set Page Start Address for Page Addressing Mode,0-7
  7.         WriteCmd(0xc8);        //Set COM Output Scan Direction
  8.         WriteCmd(0x81);  //--set contrast control register
  9.         WriteCmd(0xff);   //亮度调节 0x00~0xff
  10.         WriteCmd(0xa1);  //--set segment re-map 0 to 127
  11.         WriteCmd(0xa6);  //--set normal display
  12.         WriteCmd(0xa8);  //--set multiplex ratio(1 to 64)
  13.         WriteCmd(0x1F);
  14.         WriteCmd(0xd3);  //-set display offset
  15.         WriteCmd(0x00);  //-not offset
  16.         WriteCmd(0xd5);  //--set display clock divide ratio/oscillator frequency
  17.         WriteCmd(0xf0);  //--set divide ratio
  18.         WriteCmd(0xd9);  //--set pre-charge period
  19.         WriteCmd(0x22);
  20.         WriteCmd(0xda);  //--set com pins hardware configuration
  21.         WriteCmd(0x02);
  22.         WriteCmd(0xdb);  //--set vcomh
  23.         WriteCmd(0x49);
  24.         WriteCmd(0x8d);  //--set DC-DC enable
  25.         WriteCmd(0x14);
  26.         WriteCmd(0xaf);  //--turn on oled panel
  27. }

实现数据填充全屏的函数为:
  1. void OLED_Fill(unsigned char fill_Data)
  2. {
  3.         unsigned char m,n;
  4.         for(m=0;m<8;m++)
  5.         {
  6.                   WriteCmd(0xb0+m);                //page0-page1
  7.                   WriteCmd(0x00);                    //low column start address
  8.                   WriteCmd(0x10);                    //high column start address
  9.                   for(n=0;n<128;n++)
  10.                   {
  11.                                 WriteDat(fill_Data);
  12.                   }
  13.         }
  14. }

实现字符串显示的函数为:
  1. void OLED_ShowStr(unsigned char x, unsigned char y, unsigned char ch[], unsigned char TextSize)
  2. {
  3.         unsigned char c = 0,i = 0,j = 0;
  4.         switch(TextSize)
  5.         {
  6.                 case 1:
  7.                 {
  8.                         while(ch[j] != '\0')
  9.                         {
  10.                                 c = ch[j] - 32;
  11.                                 if(x > 126)
  12.                                 {
  13.                                         x = 0;
  14.                                         y++;
  15.                                 }
  16.                                 OLED_SetPos(x,y);
  17.                                 for(i=0;i<6;i++)
  18.                                         WriteDat(F6x8[c][i]);
  19.                                 x += 6;
  20.                                 j++;
  21.                         }
  22.                 }
  23.                 break;
  24.                 case 2:
  25.                 {
  26.                         while(ch[j] != '\0')
  27.                         {
  28.                                 c = ch[j] - 32;
  29.                                 if(x > 120)
  30.                                 {
  31.                                         x = 0;
  32.                                         y++;
  33.                                 }
  34.                                 OLED_SetPos(x,y);
  35.                                 for(i=0;i<8;i++)
  36.                                         WriteDat(F8X16[c*16+i]);
  37.                                 OLED_SetPos(x,y+1);
  38.                                 for(i=0;i<8;i++)
  39.                                         WriteDat(F8X16[c*16+i+8]);
  40.                                 x += 8;
  41.                                 j++;
  42.                         }
  43.                 }
  44.                 break;
  45.         }
  46. }

测试以硬件方式驱动OLED显示屏并显示字符串信息的主程序为:
  1. int main(void)
  2. {
  3.         HAL_Init();
  4.         SystemClock_Config();
  5.         MX_GPIO_Init();
  6.         MX_I2C1_Init();
  7.         MX_ICACHE_Init();
  8.         BSP_LED_Init(LD2);
  9.         BSP_PB_Init(BUTTON_USER, BUTTON_MODE_GPIO);        
  10.         MX_I2C2_Init();
  11.         OLED_Init();
  12.         OLED_Fill(0x00);
  13.         OLED_ShowStr(0,0,"STM32U385",2);
  14.         OLED_ShowStr(0,2,"I2C OLED TEST",2);        
  15.         while (BSP_PB_GetState(BUTTON_USER) != GPIO_PIN_SET);
  16. }

经程序的编译和下载,其测试效果如图1和图2所示。
1.jpg
1 驱动0.91寸屏

2.jpg
2 驱动0.96寸屏


2. RTC时钟

要使用片内的RTC实现电子时钟功能,需要先对RTC进行初始化设置,其对应的函数为:
  1. static void MX_RTC_Init(void)
  2. {
  3.   RTC_PrivilegeStateTypeDef privilegeState = {0};
  4.   RTC_TimeTypeDef sTime = {0};
  5.   RTC_DateTypeDef sDate = {0};
  6.   RTC_AlarmTypeDef sAlarm = {0};
  7.   hrtc.Instance = RTC;
  8.   hrtc.Init.HourFormat = RTC_HOURFORMAT_24;
  9.   hrtc.Init.AsynchPrediv = 127;
  10.   hrtc.Init.SynchPrediv = 255;
  11.   hrtc.Init.OutPut = RTC_OUTPUT_DISABLE;
  12.   hrtc.Init.OutPutRemap = RTC_OUTPUT_REMAP_NONE;
  13.   hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
  14.   hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
  15.   hrtc.Init.OutPutPullUp = RTC_OUTPUT_PULLUP_NONE;
  16.   hrtc.Init.BinMode = RTC_BINARY_NONE;
  17.   if (HAL_RTC_Init(&hrtc) != HAL_OK)
  18.   {
  19.     Error_Handler();
  20.   }
  21.   privilegeState.rtcPrivilegeFull = RTC_PRIVILEGE_FULL_NO;
  22.   privilegeState.backupRegisterPrivZone = RTC_PRIVILEGE_BKUP_ZONE_NONE;
  23.   privilegeState.backupRegisterStartZone2 = RTC_BKP_DR0;
  24.   privilegeState.backupRegisterStartZone3 = RTC_BKP_DR0;
  25.   if (HAL_RTCEx_PrivilegeModeSet(&hrtc, &privilegeState) != HAL_OK)
  26.   {
  27.     Error_Handler();
  28.   }
  29.   sTime.Hours = 0x2;
  30.   sTime.Minutes = 0x20;
  31.   sTime.Seconds = 0x0;
  32.   sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
  33.   sTime.StoreOperation = RTC_STOREOPERATION_RESET;
  34.   if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BCD) != HAL_OK)
  35.   {
  36.     Error_Handler();
  37.   }
  38.   sDate.WeekDay = RTC_WEEKDAY_TUESDAY;
  39.   sDate.Month = RTC_MONTH_JULY ;
  40.   sDate.Date = 0x15;
  41.   sDate.Year = 0x25;
  42.   if (HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BCD) != HAL_OK)
  43.   {
  44.     Error_Handler();
  45.   }
  46.   sAlarm.AlarmTime.Hours = 0x2;
  47.   sAlarm.AlarmTime.Minutes = 0x20;
  48.   sAlarm.AlarmTime.Seconds = 0x30;
  49.   sAlarm.AlarmTime.SubSeconds = 0x56;
  50.   sAlarm.AlarmMask = RTC_ALARMMASK_NONE;
  51.   sAlarm.AlarmSubSecondMask = RTC_ALARMSUBSECONDMASK_ALL;
  52.   sAlarm.AlarmDateWeekDaySel = RTC_ALARMDATEWEEKDAYSEL_WEEKDAY;
  53.   sAlarm.AlarmDateWeekDay = RTC_WEEKDAY_MONDAY;
  54.   sAlarm.Alarm = RTC_ALARM_A;
  55.   if (HAL_RTC_SetAlarm_IT(&hrtc, &sAlarm, RTC_FORMAT_BCD) != HAL_OK)
  56.   {
  57.     Error_Handler();
  58.   }
  59. }

实现时钟显示功能的函数为:
  1. static void RTC_TimeShow(uint8_t *showtime)
  2. {
  3.    RTC_DateTypeDef sdatestructureget;
  4.    RTC_TimeTypeDef stimestructureget;
  5.    HAL_RTC_GetTime(&hrtc, &stimestructureget, RTC_FORMAT_BIN);
  6.    HAL_RTC_GetDate(&hrtc, &sdatestructureget, RTC_FORMAT_BIN);
  7.    sprintf((char *)showtime, "%02d:%02d:%02d", stimestructureget.Hours, stimestructureget.Minutes, stimestructureget.Seconds);
  8.    OLED_ShowString(0,2,showtime,16);        
  9. }

测试电子时钟计时与显示功能的主程序为:
  1. int main(void)
  2. {
  3.   HAL_Init();
  4.   HAL_PWR_EnableBkUpAccess();
  5.   SystemClock_Config();
  6.   MX_GPIO_Init();
  7.   MX_RTC_Init();
  8.   MX_ICACHE_Init();
  9.   BSP_LED_Init(LD2);
  10.   RTCStatus = 1;        
  11.   I2C_CONFIG();
  12.   HAL_Delay(50);
  13.   OLED_Init();
  14.   OLED_Clear();
  15.   OLED_ShowString(0,0,"STM32U385 RTC",16);        
  16.   while (1)
  17.   {
  18.        RTC_TimeShow(aShowTime);
  19.   }
  20. }

经程序的编译和下载,其测试效果如图3所示。
3.jpg
3 电子时钟计时效果


演示视频:

小小蚂蚁举千斤 发表于 2025-7-28 23:31 | 显示全部楼层
OLED屏显示驱动与RTC时钟
您需要登录后才可以回帖 登录 | 注册

本版积分规则

517

主题

2932

帖子

39

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