【前言】
在工程https://forum.eepw.com.cn/thread/389948/1的基础之上,添加IIC的OLED驱动,再添加RTC实现时钟的基本驱动。
【步骤】
1、选取IIC的管脚与开发板的EEPROM一致,从开发板的原理图可以看到他为PC6-SCL,PC7为SDA
2、编写IIC初始化。
我这次OLED采取了整个显存,然后用分页进行发送,因此配置为DMA发送:
void OLED_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct; I2C_InitTypeDef I2C_InitStruct; RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE); I2C_DeInit(I2C1); I2C_StructInit(&I2C_InitStruct); I2C_InitStruct.I2C_Mode = I2C_MODE_MASTER; I2C_InitStruct.I2C_OwnAddress = I2C_OWN_ADDRESS; I2C_InitStruct.I2C_ClockSpeed = 1000000; I2C_Init(I2C1, &I2C_InitStruct); I2C_TargetAddressConfig(I2C1, OLED_I2C_ADDRESS); RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE); GPIO_PinAFConfig(GPIOC, GPIO_PinSource6, GPIO_AF_4); GPIO_PinAFConfig(GPIOC, GPIO_PinSource7, GPIO_AF_4); GPIO_StructInit(&GPIO_InitStruct); GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_High; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_OD; GPIO_Init(GPIOC, &GPIO_InitStruct); I2C_Cmd(I2C1, ENABLE); }
DMA发送函数如下:
void OLED_TxData_DMA_Polling(uint8_t *Buffer, uint8_t Length) { DMA_InitTypeDef DMA_InitStruct; RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); DMA_DeInit(DMA1_Channel6); DMA_StructInit(&DMA_InitStruct); DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&(I2C1->DR); DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)Buffer; DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralDST; DMA_InitStruct.DMA_BufferSize = Length; DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word; DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; DMA_InitStruct.DMA_Mode = DMA_Mode_Normal; DMA_InitStruct.DMA_Priority = DMA_Priority_Low; DMA_InitStruct.DMA_M2M = DMA_M2M_Disable; DMA_InitStruct.DMA_Auto_Reload = DMA_Auto_Reload_Disable; DMA_Init(DMA1_Channel6, &DMA_InitStruct); I2C_DMACmd(I2C1, I2C_DMA_TXEN, ENABLE); DMA_Cmd(DMA1_Channel6, ENABLE); while (RESET == DMA_GetFlagStatus(DMA1_FLAG_TC6)) { } I2C_DMACmd(I2C1, I2C_DMA_TXEN, DISABLE); DMA_Cmd(DMA1_Channel6, DISABLE); }
发送命令,只需要发送两个字节,所以不需要采取DMA发送,函数如下:
void I2C_TxData_Polling(uint8_t *Buffer, uint8_t Length) { uint8_t i = 0; for (i = 0; i < Length; i++) { I2C_SendData(I2C1, Buffer[i]); while (RESET == I2C_GetFlagStatus(I2C1, I2C_STATUS_FLAG_TFE)) { } } I2C_GenerateSTOP(I2C1, ENABLE); while (RESET == I2C_GetFlagStatus(I2C1, I2C_STATUS_FLAG_TFE)) { } }
再编写发送指令与数据的两个关键函数:
/** * 函 数:OLED写数据 * 参 数:Data 要写入数据的起始地址 * 参 数:Count 要写入数据的数量 * 返 回 值:无 */ void OLED_WriteData(uint8_t *Data, uint8_t Count) { uint8_t dat[1]; dat[0]= 0x40; OLED_TxData_DMA_Polling(dat,1); OLED_TxData_DMA_Polling(Data,Count); I2C_GenerateSTOP(I2C1, ENABLE); while (RESET == I2C_GetFlagStatus(I2C1, I2C_STATUS_FLAG_TFE)) { } } /** * 函 数:OLED写命令 * 参 数:Command 要写入的命令值,范围:0x00~0xFF * 返 回 值:无 */ void OLED_WriteCommand(uint8_t Command) { uint8_t commadDat[2]; commadDat[0] = 0x00; commadDat[1] = Command; I2C_TxData_Polling(commadDat, 2); }
到此IIC的移植就可以了。
【RTC移植】
复制官方示例到工程之中,在mm32f5370_it.c中添加中断回调函数:
void RTC_IRQHandler(void) { if (RTC_GetITStatus(RTC_IT_SEC) != RESET) { RTC_UpdateCalendar(); RTC_ClearITPendingBit(RTC_IT_SEC); RTC_WaitForLastTask(); } }
在main.c中添加OLED显示任务:
void led1_task(void *pvParameters) { while(1) { OLED_Printf(0,16,OLED_8X16,"%02d:%02d:%02d", RTC_Calendar.hour,RTC_Calendar.minute,RTC_Calendar.second); OLED_Update(); GPIO_WriteBit(GPIOB, GPIO_Pin_15, 0); vTaskDelay(500); GPIO_WriteBit(GPIOB, GPIO_Pin_15, 1); vTaskDelay(500); } }
实现效果:
下载到开发板后,就可以看到实时运行的时钟了。