班 级 计科223
姓 名 孙傲
学 号 2130110259
指导教师 卢春红
设计时间 2025/1/1
2024 —— 2025 学年第 一 学期
傲哥小记:
孙某自习嵌入式技术,初涉其门,茫然若失。然渐入佳境,方觉其奥妙无穷,乐此不疲。此道既深且广,涵盖硬件与软件之精髓,融汇调试与优化之巧,实为工艺之高也。每一实验,犹若修身齐家,细致入微;每一编程,犹如治国理政,层层递进。是以,我溺此道之中,得以悟其妙理,深感收获颇丰,今愿以笔述其所学,以明其心。
始也,若以为嵌入式不过是机巧之术,殊不知其蕴藏诸多精深之理。串口通信,乃此术之基也。余初学时,未尝知何为“RDR寄存器”,何为“中断接收”。及至操作,始知此法之妙,犹如精工巧匠,精细调控每一丝每一毫。数据字节传送,瞬息之间,指令送达,回音复返。每一次的字符传输,仿佛有丝线相连,机电之间互通有无,心领神会。控制之灯如流水般起伏,彼时彼刻,何其畅快!
至于定时器与中断,亦为此道之大要。定时器者,犹如掌中之钟,分秒必争。利其调度,度之节奏,如指挥大军行进,精准有序。余用定时器现三色灯依时交替。时光流转,光辉变换,仿佛与天同步,顺应四时之律。此之操作,使我深感时空之流动,机器之默契。
而PWM控制,乃为心灯之技也。此法似能使光亮之强弱,随意调控,如同掌控心境之起伏。通过数字0至100,操控占空比控LED光亮强度,仿佛成了光的主宰。每一微小变化,直接感知,犹如调节内心澄明昏暗,尽在掌控之间。
更有实时操作系统(RTOS)中之线程管理,令我如见帝王之权谋,众事齐行,各有其时,井然有序。流水灯之效果,正是通过线程交替实现,犹如庙堂之高,权力之分配,微妙且灵活。每一任务,各司其职,互不干扰,恰如大明宫中权臣与国君,精妙协作,运转如常。
Flash存储与数据持久化操作,亦让我得以深悟“存与取”之道。通过串口操作,数据之写入与读取,犹如春秋之藏,固守智慧与经历。时间数据写入,并在每次开机时自动展示,犹如记忆之门,开启时刻,往事历历在目。余在此道上,领略了数据存储与提取之奥义,再现数据库与图片存储之大能,方知科技亦可承载历史与智慧,纵使时光荏苒,信息亦能历久弥新。
此等诸般技术,均是嵌入式之精髓,兼顾软件硬件之默契,正是技术之艺术。每一次代码之敲定,灯光之辉,乃是心机与智慧结晶。此道机械的操控,更为智慧的呈现与灵魂的表达。嵌入式之学,教我如何与世界对话,如何让机器理解人类的意图;如何在有限的硬件资源下,实现无限的创意与梦想。
余今得此,深感荣幸,未来当更加精进,欲在此道上求得真知,通达其理,化繁为简,使机械更懂人心。
第七周:
实验目的与要求:
1、增加利用RDR寄存器接收一个字节并回送至PC功能(直接地址法);
2、修改初始化函数的相关寄存器:数据帧:7(数据位)+2/1(停止位),波特率:9600,利用PC软件测试收发(直接地址法)
3、参考MCU 串口中断样例程序,利用该程序框架实现:通过串口调试工具,PC 机发送字符‘1’或者‘0’来控制开发板上三色灯,MCU 的接收到字符‘1’时打开灯,接收到字符‘0’时关闭灯
4、参考MCU 串口中断样例程序,利用该程序框架实现:通过串口调试工具,PC 机发送字符‘1’或者‘0’来控制一个LED灯,MCU 的接收到字符‘1’时打开LED灯,接收到字符‘0’时关闭LED灯(自己外接LED灯)。
5、参考MCU 串口中断样例程序,,结合之前流水灯实验,实现串口 发送数字1、2、3、4控制四种流水灯
6、参考MCU 串口中断样例程序,利用该程序框架实现:通过串口调试工具,PC 机发送字符串“Open”或者“Close” 来控制开发板上三色灯中的一个LED 灯,MCU 的接收到字符串“Open”时打开LED 灯,接收到字符串“Close”时关闭LED 灯。参考组帧程序编写
实验过程与数据记录:
1. uint8_t uart_re1(uint8_t uartNo,uint8_t *fp)
{
uint32_t t;
uint8_t dat;
//判断传入串口号参数是否有误,有误直接退出
if(!uart_is_uartNo(uartNo)) return 0;
//判断传入串口号参数是否有误,有误直接退出
if(!uart_is_uartNo(uartNo))
{
*fp=0;
return 0;
}
for (t = 0; t < 0xFBBB; t++)//查询指定次数
{
//判断接收缓冲区是否满
if (USART_ARR[uartNo-1]->ISR & USART_ISR_RXNE_Msk)
{
dat=USART_ARR[uartNo-1]->RDR; //获取数据,清接收中断位
*fp = 1; //接收成功
break;
}
}//end for
if(t >= 0xFBBB)
{
dat = 0xFF;
*fp = 0; //未收到数据
}
return dat; //返回接收到的数据
}
使用方法也很简单,received_data = uart_re1(uart, &result_flag);可以实现接收串口发送的数据。
2. uint8_t uart_send1(uint8_t uartNo, uint8_t ch)
{ uint32_t t;
//判断传入串口号参数是否有误,有误直接退出
if(!uart_is_uartNo(uartNo)) return 0;
for (t = 0; t < 0xFBBB; t++)//查询指定次数
{
//发送缓冲区为空则发送数据
if ( USART_ARR[uartNo-1]->ISR & USART_ISR_TXE_Msk )
{
USART_ARR[uartNo-1]->TDR = ch;
break;
}
}//end for
if (t >= 0xFBBB)
return 0; //发送超时,发送失败
else
return 1; //成功发送
}
可以通过uart_send1(uartNo, str);来实现数据的回发
uart_init(UART_User,9600);可以用来初始化串口
//发送“数字48~100”
for (mi=0;mi<=255;mi++)
{
uart_send1(UART_User,mi);
}
uart_send_string(UART_User,(uint8_t *)"---");
可以看到这个是实现发送0到255数据的示例
3. uint8_t sun;
uint8_t receivedData; // 接收到的数据
uint8_t ledState = LIGHT_OFF; // 红灯状态变量(初始为关闭)
receivedData = uart_re1(UART_User, &sun);
// 根据接收到的数据控制红灯
if (receivedData == 1 && ledState == LIGHT_OFF) {
gpio_set(LIGHT_RED, LIGHT_ON);
ledState = LIGHT_ON; // 更新红灯状态
} else if (receivedData == 0 && ledState == LIGHT_ON) {
gpio_set(LIGHT_RED, LIGHT_OFF);
ledState = LIGHT_OFF; // 更新红灯状态
}
这个关键的部分是用来实现判断接收到1实现板子三色灯亮,接收到0实现板子三色灯灭的关键代码。
4.
#define LIGHT1 (PTA_NUM|8)
#define LIGHT2 (PTB_NUM|11)
receivedData = uart_re1(UART_User, &sun);
// 根据接收到的数据控制红灯
if (receivedData == 1 && ledState == LIGHT_OFF) {
gpio_set(LIGHT1, LIGHT_ON);
ledState = LIGHT_ON; // 更新红灯状态
} else if (receivedData == 0 && ledState == LIGHT_ON) {
gpio_set(LIGHT1, LIGHT_OFF);
ledState = LIGHT_OFF; // 更新红灯状态
}
这个关键的部分是用来实现判断接收到1实现板子外接灯亮,接收到0实现板子外接灯灭的关键代码。
5.
receivedData = uart_re1(UART_User, &sun);
// 根据接收到的数据控制红灯
if (receivedData == 1 && ledState == 1) {
gpio_set(LIGHT_RED, LIGHT_ON);
gpio_set(LIGHT_BLUE, LIGHT_OFF);
gpio_set(LIGHT_GREEN, LIGHT_OFF);
ledState = 2; // 更新红灯状态
printf("红灯:亮\n");
} else if (receivedData == 2 && ledState == 2) {
gpio_set(LIGHT_RED, LIGHT_OFF);
gpio_set(LIGHT_BLUE, LIGHT_ON);
gpio_set(LIGHT_GREEN, LIGHT_OFF);
ledState = 3; // 更新红灯状态
printf("蓝灯:亮\n");
} else if (receivedData == 3 && ledState == 3) {
gpio_set(LIGHT_RED, LIGHT_OFF);
gpio_set(LIGHT_BLUE, LIGHT_OFF);
gpio_set(LIGHT_GREEN, LIGHT_ON);
ledState = 4; // 更新红灯状态
printf("绿灯:亮\n");
} else if (receivedData == 4 && ledState == 4) {
gpio_set(LIGHT_RED, LIGHT_ON);
gpio_set(LIGHT_BLUE, LIGHT_OFF);
gpio_set(LIGHT_GREEN, LIGHT_ON);
ledState = 1; // 更新红灯状态
printf("黄灯:亮\n");
}
这段代码可以用于一个类似交通信号灯控制系统的场景,在该场景中,串口通信用来接收指令来控制不同颜色的 LED 灯。接收到的不同指令(1, 2, 3, 4)代表不同的灯状态,并且可以根据当前状态进行灯光的切换。
6.组帧函数如下
#define FrameHead (0x50) //帧头 ASCII码对应P
#define FrameTail (0x43) //帧尾 ASCII码对应C
//P4openC
uint8_t CreateFrame(uint8_t Data,uint8_t * buffer)
{
static uint8_t frameLen=0; //帧的计数器
uint8_t frameFlag; //组帧状态
frameFlag=0; //组帧状态初始化
//根据静态变量frameCount组帧
switch(frameLen)
{
case 0: //第一个数据
{
if (Data==FrameHead) //收到数据是帧头FrameHead
{
buffer[0]=Data;
frameLen++;
frameFlag=0; //组帧开始
}
break;
}
case 1: //第二个数据,该数据是随后接收的数据个数
{
buffer[1]=Data-0x30;
frameLen++;
break;
}
default: //其他情况
{
//第二位数据是有效数据长度,根据它接收余下的数据直到帧尾前一位
if(frameLen>=2 && frameLen<=(buffer[1] + 1))
{
buffer[frameLen]=Data;
frameLen++;
break;
}
//若是末尾数据则执行
if(frameLen>=(buffer[1]+2))
{
if (Data==FrameTail) //若是帧尾
{
buffer[frameLen]=Data; //将帧尾存入缓冲区
frameFlag=1; //组帧成功
}
frameLen=0 ; //计数清0,准备重新组帧
break;
}
}
} //switch_END
return frameFlag; //返回组帧状态
}
这个函数实现了一个简单的帧解析机制,用于接收和组装一个特定格式的数据帧。
数据帧的格式由帧头、数据长度、有效数据和帧尾组成。
CreateFrame 函数通过逐字节接收数据并根据帧格式进行处理,最后返回帧是否组装成功的标志。
在嵌入式系统中,DISABLE_INTERRUPTS 和 ENABLE_INTERRUPTS 是用于控制中断使能的宏,它们的作用是在执行某些关键操作时禁用和启用中断,以保证操作的原子性和防止中断干扰。
void UART_User_Handler(void) {
uint8_t ch, flag;
DISABLE_INTERRUPTS; // 关总中断
ch = uart_re1(UART_User, &flag); // 接收一个字节
// 调用内部函数CreateFrame进行组帧
if (CreateFrame(ch, g_uart_recvBuf) != 0) { // 组帧成功
// 如果收到“Open”命令
if (strncmp((const char*)&g_uart_recvBuf[2], "Open", 4) == 0) {
gpio_set(LIGHT_BLUE, LIGHT_ON); // 打开LED灯
uart_send1(UART_User,ch);
}
// 如果收到“Close”命令
else if (strncmp((const char*)&g_uart_recvBuf[2], "Close", 5) == 0) {
gpio_set(LIGHT_BLUE, LIGHT_OFF); // 关闭LED灯
uart_send1(UART_User,ch);
}
// 其他命令的处理(如果需要)
}
ENABLE_INTERRUPTS; // 开总中断
}
UART_User_Handler 函数的流程:
关中断 (DISABLE_INTERRUPTS),确保函数执行过程不被打断。
接收数据:调用 uart_re1 函数接收一个字节的数据,并根据接收到的数据进行帧的组装。
解析命令:
如果接收到的数据帧中包含 "Open" 命令,则打开蓝色 LED 灯。
如果接收到的数据帧中包含 "Close" 命令,则关闭蓝色 LED 灯。
响应数据:根据命令,向串口发送响应数据。
开中断 (ENABLE_INTERRUPTS),允许中断响应系统的其他事件
第八周:
实验目的与要求:
1. 利用组帧方法完成C#方和MCU方程序功能,C#方程序实现鼠标单击相应按钮,控制开发板上的三色灯完成“红、绿、蓝、青、紫、黄、白、暗”显示的控制。
2. 修改流水灯实验,通过systick定时器实现延时
3. 用systick模块,实现蓝灯亮2秒,红灯亮4秒,绿灯亮6秒的交替循环变化
4. 自行编写上位机软件,通过串口设置定时器初始计时时间,(也可以自动获取系统时间)
实验过程与数据记录:
1.
金葫芦里中断函数
void UART_User_Handler(void) {
uint8_t ch, flag;
DISABLE_INTERRUPTS; // 关总中断
ch = uart_re1(UART_User, &flag); // 接收一个字节
// 调用内部函数CreateFrame进行组帧
if (CreateFrame(ch, g_uart_recvBuf) != 0) { // 组帧成功
// 如果收到“Open”命令
if (strncmp((const char*)&g_uart_recvBuf[2], "open1", 5) == 0) {
gpio_set(LIGHT_BLUE, LIGHT_OFF); // 打开LED灯
gpio_set(LIGHT_GREEN, LIGHT_OFF);
gpio_set(LIGHT_RED, LIGHT_ON);
uart_send1(UART_User,ch);
}
// 如果收到“Close”命令
else if (strncmp((const char*)&g_uart_recvBuf[2], "open2", 5) == 0) {
gpio_set(LIGHT_BLUE, LIGHT_ON); // 关闭LED灯
gpio_set(LIGHT_GREEN, LIGHT_OFF);
gpio_set(LIGHT_RED, LIGHT_OFF);
uart_send1(UART_User,ch);
}
else if (strncmp((const char*)&g_uart_recvBuf[2], "open3", 5) == 0) {
gpio_set(LIGHT_BLUE, LIGHT_OFF); // 关闭LED灯
gpio_set(LIGHT_GREEN, LIGHT_ON);
gpio_set(LIGHT_RED, LIGHT_OFF);
uart_send1(UART_User,ch);
}
else if (strncmp((const char*)&g_uart_recvBuf[2], "open4", 5) == 0) {
gpio_set(LIGHT_BLUE, LIGHT_ON); // 关闭LED灯
gpio_set(LIGHT_GREEN, LIGHT_ON);
gpio_set(LIGHT_RED, LIGHT_OFF);
uart_send1(UART_User,ch);
}
else if (strncmp((const char*)&g_uart_recvBuf[2], "open5", 5) == 0) {
gpio_set(LIGHT_BLUE, LIGHT_ON); // 关闭LED灯
gpio_set(LIGHT_GREEN, LIGHT_OFF);
gpio_set(LIGHT_RED, LIGHT_ON);
uart_send1(UART_User,ch);
}
else if (strncmp((const char*)&g_uart_recvBuf[2], "open6", 5) == 0) {
gpio_set(LIGHT_BLUE, LIGHT_OFF); // 关闭LED灯
gpio_set(LIGHT_GREEN, LIGHT_ON);
gpio_set(LIGHT_RED, LIGHT_ON);
uart_send1(UART_User,ch);
}
else if (strncmp((const char*)&g_uart_recvBuf[2], "open7", 5) == 0) {
gpio_set(LIGHT_BLUE, LIGHT_ON); // 关闭LED灯
gpio_set(LIGHT_GREEN, LIGHT_ON);
gpio_set(LIGHT_RED, LIGHT_ON);
uart_send1(UART_User,ch);
}
else if (strncmp((const char*)&g_uart_recvBuf[2], "close", 5) == 0) {
gpio_set(LIGHT_BLUE, LIGHT_OFF); // 关闭LED灯
gpio_set(LIGHT_GREEN, LIGHT_OFF);
gpio_set(LIGHT_RED, LIGHT_OFF);
uart_send1(UART_User,ch);
}