本帖最后由 jinglixixi 于 2025-7-15 21:20 编辑
前面介绍了以软件模拟的方式来驱动OLED屏,有了其成功的基础再来尝试硬件的驱动方式就方便了许多,因为硬件驱动的主要工作就是配置I2C的初始化函数及变更I2C发送字节数据的发送,其他的基本无需进行调整。
1. OLED显示屏驱动 为了驱动OLED显示屏,这里使用的接口I2C2,相应的引脚连接关系为:
OLED_SCL -----I2C2_SCL----- PB13 OLED_SDA------I2C2_SDA------PB14
对I2C2的初始化函数为: - void MX_I2C2_Init(void)
- {
- hi2c2.Instance = I2C2;
- hi2c2.Init.Timing = 0x009032AE;
- hi2c2.Init.OwnAddress1 = 0;
- hi2c2.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
- hi2c2.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
- hi2c2.Init.OwnAddress2 = 0;
- hi2c2.Init.OwnAddress2Masks = I2C_OA2_NOMASK;
- hi2c2.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
- hi2c2.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
- if (HAL_I2C_Init(&hi2c2) != HAL_OK)
- {
- Error_Handler();
- }
- if (HAL_I2CEx_ConfigAnalogFilter(&hi2c2, I2C_ANALOGFILTER_ENABLE) != HAL_OK)
- {
- Error_Handler();
- }
- if (HAL_I2CEx_ConfigDigitalFilter(&hi2c2, 0) != HAL_OK)
- {
- Error_Handler();
- }
- }
实现I2C发送字节数据的函数为: - #define OLED_ADDRESS 0x78
- void I2C_WriteByte(uint8_t addr, uint8_t dat)
- {
- uint8_t temp[2];
- temp[0] = dat;
- temp[1] = dat;
- HAL_I2C_Mem_Write(&hi2c2,OLED_ADDRESS,addr,I2C_MEMADD_SIZE_8BIT,temp,1,10);
- }
实现指令发送的函数为: - void WriteCmd(unsigned char I2C_Command)
- {
- I2C_WriteByte(0x00, I2C_Command);
- }
对所用显示屏的初始化函数为: - void OLED_Init(void)
- {
- HAL_Delay(100);
- WriteCmd(0xAE); //display off
- WriteCmd(0x40);
- WriteCmd(0xb0); //Set Page Start Address for Page Addressing Mode,0-7
- WriteCmd(0xc8); //Set COM Output Scan Direction
- WriteCmd(0x81); //--set contrast control register
- WriteCmd(0xff); //亮度调节 0x00~0xff
- WriteCmd(0xa1); //--set segment re-map 0 to 127
- WriteCmd(0xa6); //--set normal display
- WriteCmd(0xa8); //--set multiplex ratio(1 to 64)
- WriteCmd(0x1F);
- WriteCmd(0xd3); //-set display offset
- WriteCmd(0x00); //-not offset
- WriteCmd(0xd5); //--set display clock divide ratio/oscillator frequency
- WriteCmd(0xf0); //--set divide ratio
- WriteCmd(0xd9); //--set pre-charge period
- WriteCmd(0x22);
- WriteCmd(0xda); //--set com pins hardware configuration
- WriteCmd(0x02);
- WriteCmd(0xdb); //--set vcomh
- WriteCmd(0x49);
- WriteCmd(0x8d); //--set DC-DC enable
- WriteCmd(0x14);
- WriteCmd(0xaf); //--turn on oled panel
- }
实现数据填充全屏的函数为: - void OLED_Fill(unsigned char fill_Data)
- {
- unsigned char m,n;
- for(m=0;m<8;m++)
- {
- WriteCmd(0xb0+m); //page0-page1
- WriteCmd(0x00); //low column start address
- WriteCmd(0x10); //high column start address
- for(n=0;n<128;n++)
- {
- WriteDat(fill_Data);
- }
- }
- }
实现字符串显示的函数为: - void OLED_ShowStr(unsigned char x, unsigned char y, unsigned char ch[], unsigned char TextSize)
- {
- unsigned char c = 0,i = 0,j = 0;
- switch(TextSize)
- {
- case 1:
- {
- while(ch[j] != '\0')
- {
- c = ch[j] - 32;
- if(x > 126)
- {
- x = 0;
- y++;
- }
- OLED_SetPos(x,y);
- for(i=0;i<6;i++)
- WriteDat(F6x8[c][i]);
- x += 6;
- j++;
- }
- }
- break;
- case 2:
- {
- while(ch[j] != '\0')
- {
- c = ch[j] - 32;
- if(x > 120)
- {
- x = 0;
- y++;
- }
- OLED_SetPos(x,y);
- for(i=0;i<8;i++)
- WriteDat(F8X16[c*16+i]);
- OLED_SetPos(x,y+1);
- for(i=0;i<8;i++)
- WriteDat(F8X16[c*16+i+8]);
- x += 8;
- j++;
- }
- }
- break;
- }
- }
测试以硬件方式驱动OLED显示屏并显示字符串信息的主程序为: - int main(void)
- {
- HAL_Init();
- SystemClock_Config();
- MX_GPIO_Init();
- MX_I2C1_Init();
- MX_ICACHE_Init();
- BSP_LED_Init(LD2);
- BSP_PB_Init(BUTTON_USER, BUTTON_MODE_GPIO);
- MX_I2C2_Init();
- OLED_Init();
- OLED_Fill(0x00);
- OLED_ShowStr(0,0,"STM32U385",2);
- OLED_ShowStr(0,2,"I2C OLED TEST",2);
- while (BSP_PB_GetState(BUTTON_USER) != GPIO_PIN_SET);
- }
经程序的编译和下载,其测试效果如图1和图2所示。 图1 驱动0.91寸屏
图2 驱动0.96寸屏
2. RTC时钟
要使用片内的RTC实现电子时钟功能,需要先对RTC进行初始化设置,其对应的函数为: - static void MX_RTC_Init(void)
- {
- RTC_PrivilegeStateTypeDef privilegeState = {0};
- RTC_TimeTypeDef sTime = {0};
- RTC_DateTypeDef sDate = {0};
- RTC_AlarmTypeDef sAlarm = {0};
- hrtc.Instance = RTC;
- hrtc.Init.HourFormat = RTC_HOURFORMAT_24;
- hrtc.Init.AsynchPrediv = 127;
- hrtc.Init.SynchPrediv = 255;
- hrtc.Init.OutPut = RTC_OUTPUT_DISABLE;
- hrtc.Init.OutPutRemap = RTC_OUTPUT_REMAP_NONE;
- hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
- hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
- hrtc.Init.OutPutPullUp = RTC_OUTPUT_PULLUP_NONE;
- hrtc.Init.BinMode = RTC_BINARY_NONE;
- if (HAL_RTC_Init(&hrtc) != HAL_OK)
- {
- Error_Handler();
- }
- privilegeState.rtcPrivilegeFull = RTC_PRIVILEGE_FULL_NO;
- privilegeState.backupRegisterPrivZone = RTC_PRIVILEGE_BKUP_ZONE_NONE;
- privilegeState.backupRegisterStartZone2 = RTC_BKP_DR0;
- privilegeState.backupRegisterStartZone3 = RTC_BKP_DR0;
- if (HAL_RTCEx_PrivilegeModeSet(&hrtc, &privilegeState) != HAL_OK)
- {
- Error_Handler();
- }
- sTime.Hours = 0x2;
- sTime.Minutes = 0x20;
- sTime.Seconds = 0x0;
- sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
- sTime.StoreOperation = RTC_STOREOPERATION_RESET;
- if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BCD) != HAL_OK)
- {
- Error_Handler();
- }
- sDate.WeekDay = RTC_WEEKDAY_TUESDAY;
- sDate.Month = RTC_MONTH_JULY ;
- sDate.Date = 0x15;
- sDate.Year = 0x25;
- if (HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BCD) != HAL_OK)
- {
- Error_Handler();
- }
- sAlarm.AlarmTime.Hours = 0x2;
- sAlarm.AlarmTime.Minutes = 0x20;
- sAlarm.AlarmTime.Seconds = 0x30;
- sAlarm.AlarmTime.SubSeconds = 0x56;
- sAlarm.AlarmMask = RTC_ALARMMASK_NONE;
- sAlarm.AlarmSubSecondMask = RTC_ALARMSUBSECONDMASK_ALL;
- sAlarm.AlarmDateWeekDaySel = RTC_ALARMDATEWEEKDAYSEL_WEEKDAY;
- sAlarm.AlarmDateWeekDay = RTC_WEEKDAY_MONDAY;
- sAlarm.Alarm = RTC_ALARM_A;
- if (HAL_RTC_SetAlarm_IT(&hrtc, &sAlarm, RTC_FORMAT_BCD) != HAL_OK)
- {
- Error_Handler();
- }
- }
实现时钟显示功能的函数为: - static void RTC_TimeShow(uint8_t *showtime)
- {
- RTC_DateTypeDef sdatestructureget;
- RTC_TimeTypeDef stimestructureget;
- HAL_RTC_GetTime(&hrtc, &stimestructureget, RTC_FORMAT_BIN);
- HAL_RTC_GetDate(&hrtc, &sdatestructureget, RTC_FORMAT_BIN);
- sprintf((char *)showtime, "%02d:%02d:%02d", stimestructureget.Hours, stimestructureget.Minutes, stimestructureget.Seconds);
- OLED_ShowString(0,2,showtime,16);
- }
测试电子时钟计时与显示功能的主程序为: - int main(void)
- {
- HAL_Init();
- HAL_PWR_EnableBkUpAccess();
- SystemClock_Config();
- MX_GPIO_Init();
- MX_RTC_Init();
- MX_ICACHE_Init();
- BSP_LED_Init(LD2);
- RTCStatus = 1;
- I2C_CONFIG();
- HAL_Delay(50);
- OLED_Init();
- OLED_Clear();
- OLED_ShowString(0,0,"STM32U385 RTC",16);
- while (1)
- {
- RTC_TimeShow(aShowTime);
- }
- }
经程序的编译和下载,其测试效果如图3所示。 图3 电子时钟计时效果
演示视频:
|