本次分享的是在恩智浦LPC824芯片上通过硬件SPI来驱动OLED屏幕,结合SysTick最终设计了一个满1小时提醒的功能。
LPC82x家族所有型号都提供了SPI接口,且包含2个SPI控制器。
• SPI功能可以通过开关矩阵(switch matrix)来配置安排到所有数字引脚。
− 建议:引脚PIO0_10和PIO0_11 (open-drain pins)不要用于SPI
• 片上ROM提供SPI驱动,即有片上ROM SPI的驱动API可供调用。
1-16位的数据帧被直接支持,更大的数据帧可结合软件来实现。
• 主/从模式。
• 支持发送数据到从设备时,无需读取进来的数据。这可用于外
接SPI存储器时。
• 可以选择将控制信息随着数据一起写入。这将允许实现多种功能的操作,包括任意长度的数据帧的操作。
• 最多4条片选输入输出信号,且极性可选,使用灵活。
• 收发支持DMA。
• 支持低功耗模式(sleep/deep sleep/power down mode)唤醒。
• 注意:不支持TI的SSI和National的Microwire模式
硬件SPI框图:
根据底板与屏幕的连接,初始化用于硬件SPI功能的相关引脚:
void OLED_SPI0_Init(void) { /* SPI initialization */ Chip_Clock_EnablePeriphClock(SYSCTL_CLOCK_SWM); Chip_SWM_MovablePinAssign(SWM_SPI0_SCK_IO, 24); Chip_SWM_MovablePinAssign(SWM_SPI0_MOSI_IO, 15); Chip_SWM_MovablePinAssign(SWM_SPI0_MISO_IO, 25); Chip_SWM_MovablePinAssign(SWM_SPI0_SSEL0_IO, 18); Chip_Clock_DisablePeriphClock(SYSCTL_CLOCK_SWM); Chip_SPI_Init(LPC_SPI0); LPC_SPI0->DIV = 30 - 1; /*配置SPI0的时钟频率为30M/300 = 100k*/ LPC_SPI0->DLY = (0 << 0) | (0 << 4) | (0 << 8) | (0 << 12); Chip_SPI_ConfigureSPI(LPC_SPI0, SPI_CFG_SPI_EN| SPI_MODE_MASTER | /* Enable master */ SPI_CLOCK_MODE0 | /* Set Clock polarity to 1 */ SPI_CFG_MSB_FIRST_EN |/* Enable MSB first option */ 0 << 7 | 0<<10); /* Chipselect is active low SSEL2 is active Low */ LPC_SPI0->TXCTRL = (0 << 18) | (1 << 20) | (1 << 21) | (1 << 22) | ((8-1) << 24); }
非常关键的OLED写数据:
void OLED_WR_Byte(u8 dat,u8 mode){ uint16_t tempDat; if(mode) OLED_DC_Set(); // mode = 1 for Data else OLED_DC_Clr(); // mode = 0 for Command. OLED_CS_Clr(); tempDat = dat; SPI_DATA_SETUP_T xfer = {0}; xfer.pTx = &tempDat; //发送数据地址 xfer.pRx = 0; //接收数据地址 xfer.DataSize = 8; //每个Frame数据大小 xfer.Length = 1; //有多少Frame Chip_SPI_WriteFrames_Blocking(LPC_SPI0, &xfer); OLED_CS_Set(); OLED_DC_Set(); }//end of OLED_WR_Byte_HwSPI
完成上述OLED写功能后,可以调用下面的代码初始化屏幕:
//OLED的初始化 void OLED_Init(void) { #if BoolHwSPI OLED_PIN_Init_HwSPI(); #else OLED_PIN_Init_SwSPI(); #endif OLED_RES_Clr(); delay_ms(200); OLED_RES_Set(); OLED_WR_Byte(0xAE,OLED_CMD);//--turn off oled panel OLED_WR_Byte(0x00,OLED_CMD);//---set low column address OLED_WR_Byte(0x10,OLED_CMD);//---set high column address OLED_WR_Byte(0x40,OLED_CMD);//--set start line address Set Mapping RAM Display Start Line (0x00~0x3F) OLED_WR_Byte(0x81,OLED_CMD);//--set contrast control register OLED_WR_Byte(0x0F,OLED_CMD);// Set SEG Output Current Brightness ,原来是0xCF,我改成了0x0F OLED_WR_Byte(0xA1,OLED_CMD);//--Set SEG/Column Mapping 0xa0左右反置 0xa1正常 OLED_WR_Byte(0xC8,OLED_CMD);//Set COM/Row Scan Direction 0xc0上下反置 0xc8正常 OLED_WR_Byte(0xA6,OLED_CMD);//--set normal display OLED_WR_Byte(0xA8,OLED_CMD);//--set multiplex ratio(1 to 64) OLED_WR_Byte(0x3f,OLED_CMD);//--1/64 duty OLED_WR_Byte(0xD3,OLED_CMD);//-set display offset Shift Mapping RAM Counter (0x00~0x3F) OLED_WR_Byte(0x00,OLED_CMD);//-not offset OLED_WR_Byte(0xd5,OLED_CMD);//--set display clock divide ratio/oscillator frequency OLED_WR_Byte(0x80,OLED_CMD);//--set divide ratio, Set Clock as 100 Frames/Sec OLED_WR_Byte(0xD9,OLED_CMD);//--set pre-charge period OLED_WR_Byte(0xF1,OLED_CMD);//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock OLED_WR_Byte(0xDA,OLED_CMD);//--set com pins hardware configuration OLED_WR_Byte(0x12,OLED_CMD); OLED_WR_Byte(0xDB,OLED_CMD);//--set vcomh OLED_WR_Byte(0x40,OLED_CMD);//Set VCOM Deselect Level OLED_WR_Byte(0x20,OLED_CMD);//-Set Page Addressing Mode (0x00/0x01/0x02) OLED_WR_Byte(0x02,OLED_CMD);// OLED_WR_Byte(0x8D,OLED_CMD);//--set Charge Pump enable/disable OLED_WR_Byte(0x14,OLED_CMD);//--set(0x10) disable OLED_WR_Byte(0xA4,OLED_CMD);// Disable Entire Display On (0xa4/0xa5) OLED_WR_Byte(0xA6,OLED_CMD);// Disable Inverse Display On (0xa6/a7) OLED_Clear(); OLED_WR_Byte(0xAF,OLED_CMD); }
在SysTick ISR中,检测按键状态:
/** * @brief Handle interrupt from SysTicKtimer * @return Nothing */ void SysTick_Handler(void) { static uint32_t count; if(BeginTime && ((count++)%TICKRATE_HZ == 0)){ testVal++; } if(keySetFlag[4]){ keySetFlag[4] = 0; testVal = 0; OLED_ShowString(104, 24, "K4", 12, 0); Chip_GPIO_PinSetState(LPC_GPIO_PORT, 0, 28, 0); delay_ms(300); Chip_GPIO_PinSetState(LPC_GPIO_PORT, 0, 28, 1); //OLED_Refresh(); } }//END OF SYSTICK_HANDLER FUNCTION
在主循环中,判断是否过了1h:
while(1){ OLED_ShowString(48, 40, testValString,12,0); OLED_Refresh(); delay_ms(100); if(testVal/3600 >=1){ Chip_GPIO_PinSetState(LPC_GPIO_PORT, 0, 28, 0); } }