一、前言
FastBond3阶段1的文档中,展示了使用Scheme-it绘制的方案框图,介绍了想要制作的开发板想法以及大概的框图原理,也说明了项目中所使用到的活动规定厂家的芯片。
在FastBond3挑战部分2中,我完成了基于STM8L051F3P6的最小系统板显示时间的项目设计。实现了OLED屏幕显示日期、时间、字符的功能,本文之后的内容将展示使用kicad继续修缮的原理图及PCB,成品的功能测试和主要程序的说明。
二、原理图及PCB介绍
原理图和PCB设计使用的都是Kicad软件,KiCad是一个开源的电子设计自动化(EDA)软件,用于设计电路板和电路图。它是最受欢迎的免费EDA工具之一,被广泛用于学术、业余爱好者和专业环境。整体原理图如下图所示,主控芯片使用的是ST公司的STM8L051F3P6芯片,STM8L051F3P6是意法半导体(STMicroelectronics)生产的一款超低功耗的8位微控制器,属于STM8系列的价值线产品。这款微控制器集成了丰富的外设和功能,包括闪存、数据EEPROM、实时时钟(RTC)、定时器、USART、I2C、SPI、ADC等,使其能够轻松集成到各种应用中,适用于需要高效能与低功耗的应用场景,如便携式设备、传感器网络、智能家居和物联网设备。它的超低功耗特性使其成为电池供电应用的理想选择。
作为一个最小系统开发板,最主要的部分就是电源、时钟和复位。
电源部分的电路如下图所示,电源采用Micro USB接口输入,使用PTC热敏电阻来防止过流,由于STM8L051F3P6的工作电源电压范围是1.8V至3.6V,所以还需要一个降压电路,我使用的是SC662K-3.3V芯片,它的最大输入电压为6V,适用于广泛的电源应用场景 ,输出电压为固定的3.3V,最大的输出电流为250mA。电源芯片的输入输出都并联了电容进行滤波。
时钟部分参考官方的数据手册进行设计,选用了32.768k的无源晶振,负载电容为8pF。
复位电路查阅官方的数据手册,复位管脚低电平电压需要小于0.8V,输入脉冲时间为50ns。所以只需要在NRST管脚给小于0.8V的电压,持续时间为50ns就可以实现复位了。但是考虑到50ns时间是很短的,很容易达到, 如果只给50ns,那么此时是有复位信号了, 但是电源还没到VCC,晶振还没起振, 这一定存在的,为了保证系统的稳定性, 这里我们取1ms的低电平时间。在直流电源作用的电路中,电容器两端的电压在经过5个时间常数后基本等于外部电压,即充电过程基本结束,1个时间常数时电压为:不满足我们的需求, 2个时间常数的时候电压为满足需求。故可以选择R为10K,C为0.1uf。
考虑做到开发板应该做得方便小巧,所以PCB布局尽可能的紧凑,好在器件并不多,所以我把器件全部放在了正面,连接器和开关靠近板边放置,采用双面布线,电源部分做了铺铜处理,设计完成的PCB如下图所示:
3D图如下图所示:
三、程序说明
主函数主要是对实时时钟(RTC)、LED、I2C和OLED显示屏进行了初始化,然后读取并显示字符和时间。
void main(void)
{
/* 使能LSE时钟 */
CLK_LSEConfig(CLK_LSE_ON);
/* 等待LSE时钟准备 */
while (CLK_GetFlagStatus(CLK_FLAG_LSERDY) == RESET);
/* 等待1S,LSE稳定 */
LSE_StabTime();
/* RTC初始化 */
Calendar_Init();
/* LED初始化 */
LED_Init();
/* IIC初始化 */
IIC_Init();
/* OLED初始化、清屏 */
OLED_Init();
OLED_Clear();
/* OLED显示字符 */
OLED_ShowString(0,0,"DATA: 20");
OLED_ShowString(80,0,"-");
OLED_ShowString(104,0,"-");
/* OLED显示字符 */
OLED_ShowString(0,2,"TIME: ");
OLED_ShowString(64,2,":");
OLED_ShowString(88,2,":");
/* OLED显示汉字 */
OLED_ShowCHinese(0,4,0);//电
OLED_ShowCHinese(18,4,1);//子
OLED_ShowCHinese(36,4,2);//森
OLED_ShowCHinese(54,4,3);//林
GPIO_ResetBits(LED1_GPIO_PORT, LED1_GPIO_PINS);
while (1)
{
Time_Show(); //读取并显示时间
Date_Show(); //读取并显示日期
}
}
Time_Show这个函数主要功能为从STM8的实时时钟(RTC)模块获取当前时间,并将时间显示在OLED屏幕上。RTC_TimeStr.RTC_Hours 是一个包含小时信息的变量,以BCD格式存储。在BCD格式中,每个十进制数字占用4位(即1个十六进制数字),因此一个字节可以表示两个十进制数字。0xF0 是一个掩码,用于提取小时的十位数字(因为十位数字在BCD中的位在高4位)。& 操作符用于将 RTC_TimeStr.RTC_Hours 与掩码相与,以获取小时的十位数字。>> 4 是一个右移操作,将提取出的十位数字右移4位,使其成为一个字节的最低位。+ 48 是将得到的二进制数转换为其ASCII码。因为ASCII码中数字'0'到'9'的值是48到57,所以通过加上48,可以将二进制数转换为对应的ASCII字符。
void Time_Show(void)
{
uint8_t Hours_D,Hours_U;
uint8_t Minutes_D,Minutes_U;
uint8_t Seconds_D,Seconds_U;
/* 等待RTC同步 */
while (RTC_WaitForSynchro() != SUCCESS);
/* 获取当前时间数据 */
RTC_GetTime(RTC_Format_BCD, &RTC_TimeStr);
/* 把读取‘时’的数据转码 */
Hours_D = (uint8_t)(((uint8_t)(RTC_TimeStr.RTC_Hours & 0xF0) >> 4) + 48);
Hours_U = (uint8_t)(((uint8_t)(RTC_TimeStr.RTC_Hours & 0x0F)) + 48);
/* 把读取‘分’的数据转码 */
Minutes_D = (uint8_t)(((uint8_t)(RTC_TimeStr.RTC_Minutes & 0xF0) >> 4) + 48);
Minutes_U = (uint8_t)(((uint8_t)(RTC_TimeStr.RTC_Minutes & 0x0F)) + 48);
/* 把读取‘秒’的数据转码 */
Seconds_D = (uint8_t)(((uint8_t)(RTC_TimeStr.RTC_Seconds & 0xF0) >> 4) + 48);
Seconds_U = (uint8_t)(((uint8_t)(RTC_TimeStr.RTC_Seconds & 0x0F)) + 48);
/* OLED上显示时、分、秒数据 */
OLED_ShowChar(48,2,Hours_D);
OLED_ShowChar(56,2,Hours_U);
OLED_ShowChar(72,2,Minutes_D);
OLED_ShowChar(80,2,Minutes_U);
OLED_ShowChar(96,2,Seconds_D);
OLED_ShowChar(104,2,Seconds_U);
}
初始化RTC的函数Calendar_Init,使用外部低速晶振(LSE)作为STM8的实时时钟(RTC)时钟源,通过分频器将时基设置为1秒。具体计算如下:
即RTC每秒钟会收到一个时钟脉冲,从而实现1秒的计时周期。
void Calendar_Init(void)
{
//选择LSE(32.768KHz)作为时钟源
CLK_RTCClockConfig(CLK_RTCCLKSource_LSE, CLK_RTCCLKDiv_1);
//打开RTC时钟
CLK_PeripheralClockConfig(CLK_Peripheral_RTC, ENABLE);
/* RTC时钟源:LSE,计时时间:32768/128/256 = 1S */
RTC_InitStr.RTC_HourFormat = RTC_HourFormat_24;//24小时制
RTC_InitStr.RTC_AsynchPrediv = 0x7F; //异步分频器 128分频
RTC_InitStr.RTC_SynchPrediv = 0x00FF; //同步分频器 256分频
RTC_Init(&RTC_InitStr); //初始化RTC参数
/* 初始化RTC_DateStr结构体,设置日期数据 */
RTC_DateStructInit(&RTC_DateStr); //初始化RTC_DateStr结构体
RTC_DateStr.RTC_WeekDay = RTC_Weekday_Thursday;//星期四
RTC_DateStr.RTC_Date = 16; //16日
RTC_DateStr.RTC_Month = RTC_Month_September; //9月
RTC_DateStr.RTC_Year = 24; //2024年
RTC_SetDate(RTC_Format_BIN, &RTC_DateStr); //设置日期数据
/* 初始化RTC_TimeStr结构体,设置时间数据 */
RTC_TimeStructInit(&RTC_TimeStr);//初始化RTC_TimeStr结构体
RTC_TimeStr.RTC_Hours = 15; //23H
RTC_TimeStr.RTC_Minutes = 20; //52分
RTC_TimeStr.RTC_Seconds = 00; //0秒
RTC_SetTime(RTC_Format_BIN, &RTC_TimeStr); //设置时间数据
}
四、成品功能测试
如下图,上电后OLED可以正常显示字符和时间
五、活动总结
通过本次活动,我能够将理论知识应用到实践中,将STM8L051F3P6的RTC使用LSE作为时钟源,往RTC写入初始化的日期&时间并在主函数循环中不断更新显示日期&时间。这种学习方式会让我对单片机的理解更加深刻,这个过程需要耐心和细致的操作。我在这个过程中培养了自己的耐心和对细节的把控。希望这个活动可以越办越好,更多人一起来学习和参与这个活动。