SPI是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线(CS、SCK、MOSI、MISO),根据实际使用情况可以只用其中的2根或3根。
MISO:主设备输入、从设备输出引脚。传输方向为从设备发送到主设备。
MOSI:主设备输出、从设备输入引脚。传输方向为主设备发送到从设备。
SCK:串口时钟,由主设备产生并提供给从设备。
NSS:从设备选择。
开发板上集成了一颗W25Q80,这是一颗容量为 8M-bit的串行 Flash 存储器
例程里有读写代码这里就不重复实现了,换用SPI驱动LCD显示屏。
驱动这块屏幕需要用到5个IO:CS、RST、A0、SCK、MOSI
初始化SPI,只用发送模式就行,手动控制CS、RST、A0
void APP_SpiInit(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
SPI_InitTypeDef SPI_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);
SPI_StructInit(&SPI_InitStruct);
SPI_InitStruct.SPI_Mode = SPI_Mode_Master;
SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStruct.SPI_DataWidth = 8;
SPI_InitStruct.SPI_CPOL = SPI_CPOL_High;
SPI_InitStruct.SPI_CPHA = SPI_CPHA_2Edge;
SPI_InitStruct.SPI_NSS = SPI_NSS_Soft;
SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16;
SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_Init(SPI1, &SPI_InitStruct);
SPI_BiDirectionalLineConfig(SPI1, SPI_Direction_Tx);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource3, GPIO_AF_5);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource5, GPIO_AF_5);
GPIO_StructInit(&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_5;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_High;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOB, &GPIO_InitStruct);
SPI_Cmd(SPI1, ENABLE);
}
void APP_SpiWriteByte(SPI_TypeDef *spix,uint8_t dat)
{
SPI_SendData(spix, dat);
while (RESET == SPI_GetFlagStatus(spix, SPI_FLAG_TXEPT));
}
YUYY_HS12864G18B_DEV_Type lcd_dev;
YUYY_GPIO_DEV_Type gpio_cs;
YUYY_GPIO_DEV_Type gpio_rst;
YUYY_GPIO_DEV_Type gpio_a0;
void APP_LcdInit(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);
GPIO_StructInit(&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_High;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOB, &GPIO_InitStruct);
gpio_cs.gpio = GPIOB;
gpio_cs.pin = GPIO_Pin_6;
gpio_a0.gpio = GPIOB;
gpio_a0.pin = GPIO_Pin_4;
gpio_rst.gpio = GPIOB;
gpio_rst.pin = GPIO_Pin_7;
lcd_dev.cs_pin = &gpio_cs;
lcd_dev.a0_pin = &gpio_a0;
lcd_dev.rst_pin = &gpio_rst;
lcd_dev.spix = SPI1;
lcd_dev.spi_sendbyte_func = (YUYY_HS12864G18B_SpiWriteByteFunc_Type)APP_SpiWriteByte;
lcd_dev.gpio_setlev_func = (YUYY_HS12864G18B_GPIO_SetLevFunc_Type)YUYY_GPIO_SetLev;
lcd_dev.delayus_func = (YUYY_HS12864G18B_DelayUsFunc_Type)YUYY_DelayUs;
YUYY_HS12864G18B_Init(&lcd_dev);
YUYY_HS12864G18B_ClearScreen(&lcd_dev);
YUYY_HS12864G18B_DisplayString8x16(&lcd_dev,0,0,0," MM32F5330 TEST");
YUYY_HS12864G18B_DisplayString8x16(&lcd_dev,0,2,0," LCD use SPI");
YUYY_HS12864G18B_DisplayString8x16(&lcd_dev,0,4,0," bbs.21ic.com");
YUYY_HS12864G18B_DisplayString8x16(&lcd_dev,0,6,0,"Code by yuyy1989");
YUYY_HS12864G18B_DisplayFinish(&lcd_dev);
}
运行效果
实时时钟(RTC)是嵌入式系统中的一种重要组件,它提供了精确的时间跟踪功能,即使在系统关机时也能保持准确。RTC通常由一个专用的硬件模块组成,用于跟踪当前的年、月、日、时、分、秒以及星期等时间信息。MM32F5330的RTC模块内部包含一组连续计数的计数器。它作为一个独立的定时器,在相应软件配置下,可提供时钟功能。修改计数器的值可以重新设置系统当前的时间。MM32F5330的RTC提供的是一个32位的计数器,需要自行实现秒到日期时间的转换
enum
{
YUYY_TIME_WEEK_SUNDAY = 0,
YUYY_TIME_WEEK_MONDAY,
YUYY_TIME_WEEK_TUESDAY,
YUYY_TIME_WEEK_WEDNESDAY,
YUYY_TIME_WEEK_THURSDAY,
YUYY_TIME_WEEK_FRIDAY,
YUYY_TIME_WEEK_SATURDAY,
};
typedef struct
{
uint8_t month;
uint8_t day;
uint8_t week;
uint8_t hour;
uint8_t minutes;
uint8_t seconds;
uint16_t year;
} YUYY_DateTimeType;
const uint8_t kMonthDays[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
bool YUYY_TIME_IsLeapYear(uint16_t year)
{
if(year%100!=0)
{
return (year%4==0);
}
else
{
return (year%400==0);
}
}
uint32_t YUYY_TIME_GetSecondFromDateTime(YUYY_DateTimeType *datetime,uint16_t since_year)
{
uint16_t i = 0,leap_count = 0;
uint32_t alldays = 0;
if(datetime->year < since_year)
return 0;
i = since_year;
while (i < datetime->year)
{
if(YUYY_TIME_IsLeapYear(i))
leap_count += 1;
i+=1;
}
alldays = (datetime->year - since_year)*365+leap_count;
printf("%d \n",leap_count);
i = 1;
while (i < datetime->month)
{
if(i == 2 && YUYY_TIME_IsLeapYear(datetime->year))
alldays += 29;
else
alldays += kMonthDays[i-1];
i+=1;
}
alldays += datetime->day - 1;
return alldays*24*3600 + datetime->hour*3600 + datetime->minutes*60 + datetime->seconds;
}
void YUYY_TIME_GetDateTimeFromSecond(uint32_t sec,YUYY_DateTimeType *datetime,uint16_t since_year,uint8_t since_week)
{
uint16_t i = 0,leap_count = 0;
uint32_t alldays = 0;
datetime->seconds = sec%60;
sec /= 60;
datetime->minutes = sec%60;
sec /= 60;
datetime->hour = sec%24;
alldays = sec/24;
i = since_year;
datetime->week = ((alldays%7)+since_week)%7;
while (alldays > 365)
{
alldays -= 365;
if(YUYY_TIME_IsLeapYear(i))
{
if(alldays>0)
alldays -= 1;
else
break;
}
i+=1;
}
datetime->year = i;
i = 0;
while (alldays >= kMonthDays[i])
{
alldays -= kMonthDays[i];
if(i == 1 && YUYY_TIME_IsLeapYear(datetime->year))
{
if(alldays > 0)
alldays -= 1;
else
break;
}
i+=1;
}
datetime->month = i+1;
datetime->day = alldays+1;
}
初始化RTC
void APP_RTCInit(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWRDBG | RCC_APB1Periph_BKP, ENABLE);
PWR_BackupAccessCmd(ENABLE);
BKP_DeInit();
if (BKP_ReadBackupRegister(BKP_DR1) != 0x5B5B)
{
RCC_LSEConfig(RCC_LSE_ON);
while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET)
{
}
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
RCC_RTCCLKCmd(ENABLE);
RTC_WaitForSynchro();
RTC_WaitForLastTask();
RTC_WaitForLastTask();
RTC_SetPrescaler(32767);
RTC_WaitForLastTask();
RTC_SetCounter(0);
RTC_WaitForLastTask();
BKP_WriteBackupRegister(BKP_DR1, 0x5B5B);
}
else
{
RTC_WaitForSynchro();
RTC_WaitForLastTask();
}
}
按下按键后修改为指定的时间
#define RTC_START_YEAR 2024
#define RTC_START_WEEK YUYY_TIME_WEEK_MONDAY
char *WeekdayStr[7]= {"SUN","MON","TUE","WED","THU","FRI","SAT"};
void APP_SetTestRTC(void)
{
YUYY_DateTimeType datetime;
datetime.year = 2024;
datetime.month = 6;
datetime.day = 30;
datetime.hour = 20;
datetime.minutes = 30;
datetime.seconds = 30;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWRDBG | RCC_APB1Periph_BKP, ENABLE);
PWR_BackupAccessCmd(ENABLE);
RTC_SetCounter(YUYY_TIME_GetSecondFromDateTime(&datetime,RTC_START_YEAR));
RTC_WaitForLastTask();
}
打印时间到LCD屏幕
int main(void)
{
char out[20];
YUYY_DateTimeType datetime;
uart_init();
led_init();
keys_init();
exit_init();
APP_SpiInit();
APP_LcdInit();
APP_RTCInit();
while (1)
{
YUYY_DelayMs(1000);
led_toggle(LED_NO_1);
YUYY_TIME_GetDateTimeFromSecond(RTC_GetCounter(),&datetime,RTC_START_YEAR,RTC_START_WEEK);
sprintf(out," %04d-%02d-%02d %s ",datetime.year, datetime.month, datetime.day,WeekdayStr[datetime.week]);
YUYY_HS12864G18B_DisplayString8x16(&lcd_dev,0,2,0,out);
sprintf(out," %02d:%02d:%02d ",datetime.hour, datetime.minutes, datetime.seconds);
YUYY_HS12864G18B_DisplayString8x16(&lcd_dev,0,4,0,out);
}
}
运行效果
|
此文章已获得独家原创/原创奖标签,著作权归21ic所有,未经允许禁止转载。
|