STM32 UART中断与新项目创建全解析
1. UART中断服务例程及相关函数
在STM32的开发中,UART(通用异步收发传输器)的中断处理是非常重要的一部分。下面我们来详细了解UART中断服务例程以及相关的函数。
1.1 UART中断服务例程(ISR)
UART中断服务例程用于处理接收到的数据。以下是
usart1_isr
函数的代码:
void usart1_isr(void) {
char ch;
BaseType_t hptask = pdFALSE;
while ( ((USART_SR(USART1) & USART_SR_RXNE) != 0) ) {
// Have received data:
ch = usart_recv(USART1);
// Use best effort to send byte to queue
xQueueSendFromISR(uart_rxq, &ch, &hptask);
}
}
这个函数的主要功能是在接收到数据时,将数据从UART接收寄存器中读取出来,并将其发送到队列
uart_rxq
中。
1.2
uart_getc
函数
uart_getc
函数用于从队列中获取接收到的数据。代码如下:
static char uart_getc(void) {
char ch;
while ( xQueueReceive(uart_rxq, &ch, 0) != pdPASS )
taskYIELD();
gpio_toggle(GPIOC, GPIO13);
return ch;
}
当队列中有数据时,函数会将数据取出并返回;如果队列中没有数据,函数会让出CPU控制权,等待数据的到来。
1.3
main_task
函数
main_task
函数是一个任务,其主要功能是接收字符并将其发送回UART。代码如下:
#define INVERT_CASE 0
static void main_task(void *args __attribute((unused))) {
for (;;) {
// Block until char received
char ch = uart_getc();
#if INVERT_CASE
if ( islower(ch) )
ch = toupper(ch);
else if ( isupper(ch) )
ch = tolower(ch);
#endif
uart_putc(ch);
}
}
通过修改
INVERT_CASE
的值为1,可以将接收到的字符进行大小写转换。
1.4
uart_putc
函数
uart_putc
函数用于将字符发送到UART。代码如下:
static inline void uart_putc(char ch) {
// Queue the byte to send
while ( xQueueSend(uart_txq, &ch, 0) != pdPASS )
taskYIELD();
if ( ch == '\n' ) {
// When we see LF, also send CR
ch = '\r';
while ( xQueueSend(uart_txq, &ch, 0) != pdPASS )
taskYIELD();
}
}
该函数会将字符发送到队列
uart_txq
中,如果队列已满,函数会让出CPU控制权。
1.5
tx_task
函数
tx_task
函数用于从队列中取出字符并发送到UART。代码如下:
static void tx_task(void *args __attribute((unused))) {
char ch;
for (;;) {
while ( xQueueReceive(uart_txq, &ch, portMAX_DELAY) != pdPASS )
taskYIELD();
// Received a char to transmit:
while ( !usart_get_flag(USART1, USART_SR_TXE) )
taskYIELD(); // Not ready to send
usart_send(USART1, ch);
}
}
当队列中有数据时,函数会等待UART准备好接收数据,然后将数据发送出去。
2. 运行演示
在运行演示之前,需要进行一些配置。
2.1 配置演示
-
修改
INVERT_CASE的值来决定是否对数据进行大小写转换。
#define INVERT_CASE 0
- 重新构建项目:
$ make clobber
$ make
- 烧录程序:
$ make flash
2.2 配置终端
连接串口设备到STM32并插入USB端口后,启动
minicom
(或其他终端模拟器):
$ minicom -D /dev/cu.usbserial-A50285BI -s
确保在
minicom
中关闭流控制,并将波特率和其他串口参数配置为115200波特,模式8N1。
2.3 演示操作
进入
minicom
的文件传输协议配置选项,添加一个名为“cat”的新协议。然后按下
Meta - S
调用“Upload”菜单,选择“cat”,可以选择一个文本文件进行传输。
3. 数据丢失问题
由于演示中没有启用流控制,在高波特率下可能会出现数据丢失的问题。可以通过降低波特率来尝试消除数据丢失。同时,STM32 USART设备和
libopencm3
库支持硬件流控制,但将其集成到程序中超出了本文的范围。
4. 新项目创建
创建一个新的STM32项目可以按照以下步骤进行:
4.1 项目创建
首先,定位到正确的起始目录:
$ cd ~/stm32f103c8t6/rtos
然后,使用
make
命令创建项目:
$ make -f Project.mk PROJECT=myproj
创建完成后,项目子目录会被填充一些文件,包括
FreeRTOSConfig.h
、
Makefile
、
main.c
等。
4.2 Makefile相关宏
Makefile
中使用了一些宏来定义项目,下面是一些重要的宏:
-
BINARY
:定义编译后的可执行文件的名称,默认是
main
。
-
SRCFILES
:定义要编译到最终可执行文件中的源文件名称,默认包括
main.c
、
rtos/heap_4.c
等。
-
LDSCRIPT
:指向项目目录中的链接脚本文件,通常为
stm32f103c8t6.ld
。
-
DEPS
:用于定义特殊的依赖项。
-
CLOBBER
:用于定义在
make clobber
时要删除的文件。
以下是默认的
Makefile
代码:
#########################################################
# Project Makefile
#########################################################
BINARY = main
SRCFILES = main.c rtos/heap_4.c rtos/list.c rtos/port.c \
rtos/queue.c rtos/tasks.c rtos/opencm3.c
LDSCRIPT = stm32f103c8t6.ld
# DEPS = # Any additional dependencies for your build
# CLOBBER += # Any additional files to be removed with \
"make clobber"
include ../../Makefile.incl
include ../Makefile.rtos
#########################################################
# NOTES:
# 1. remove any modules you don't need from SRCFILES
# 2. "make clean" will remove *.o etc., but leaves *.elf, *.bin
# 3. "make clobber" will "clean" and remove *.elf, *.bin etc.
# 4. "make flash" will perform:
# st-flash write main.bin 0x8000000
#########################################################
4.3 其他配置
-
包含的Makefile
:项目中包含了
../../Makefile.incl和../Makefile.rtos,分别用于定义项目构建的宏和规则,以及添加./rtos子目录到FreeRTOS构建的包含文件搜索路径。 -
头文件依赖
:可以通过添加
Makefile依赖规则来处理头文件的变化,例如:
main.o: myproj.h
- 编译选项 :可以为特定模块添加特殊的编译选项,例如:
ugui.o: CFLAGS += -Wno-parentheses
4.4 烧录操作
项目构建完成后,使用以下命令进行烧录:
$ make flash
对于支持128K闪存的STM32F103C8T6芯片,可以使用以下命令进行烧录:
$ make bigflash
5. FreeRTOS组件
在项目中,FreeRTOS组件是重要的一部分。其中,
rtos/opencm3.c
模块用于将
libopencm3
框架连接到FreeRTOS。以下是该模块的代码:
/* Warren W. Gay VE3WWG
*
* To use libopencm3 with FreeRTOS on Cortex - M3 platform, we must
* define three interlude routines.
*/
#include "FreeRTOS.h"
#include "task.h"
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/gpio.h>
#include <libopencm3/cm3/nvic.h>
extern void vPortSVCHandler( void ) __attribute__ (( naked ));
extern void xPortPendSVHandler( void ) __attribute__ (( naked ));
extern void xPortSysTickHandler( void );
void sv_call_handler(void) {
vPortSVCHandler();
}
void pend_sv_handler(void) {
xPortPendSVHandler();
}
void sys_tick_handler(void) {
xPortSysTickHandler();
}
/* end opncm3.c */
6. 总结
通过以上内容,我们了解了STM32 UART中断处理的相关函数和流程,以及如何创建一个新的STM32项目。在UART中断处理中,使用队列可以有效地管理接收到的数据;在项目创建过程中,合理配置
Makefile
和相关宏可以提高开发效率。同时,我们也提到了数据丢失和FreeRTOS组件等相关问题,希望对大家的开发有所帮助。
表格:Minicom “cat”文件传输协议设置
| 参数 | 值 |
|---|---|
| Name | Y |
| U/D | U |
| FullScr | Y |
| IO - Red. | Y |
| Multi | N |
流程图:新项目创建流程
graph TD;
A[定位起始目录] --> B[创建项目子目录];
B --> C[生成Makefile等文件];
C --> D[编辑FreeRTOSConfig.h];
D --> E[编辑Makefile SRCFILES];
E --> F[编辑stm32f103c8t6.ld(可选)];
F --> G[make];
G --> H[make flash];
7. 关键技术点分析
7.1 UART中断处理优势
UART中断处理通过引入接收中断,显著改善了UART接收器的性能。传统的UART外设数据寄存器容量有限,而利用FreeRTOS内核的队列结合RAM内存,有效突破了这一限制。当有数据到达时,中断服务例程(ISR)会迅速响应,将数据从UART接收寄存器读取出来,并存储到队列中。这样一来,即使数据连续快速到达,也不会因为寄存器溢出而导致数据丢失。例如,在高速数据传输场景下,中断处理能够及时捕获每一个数据,保证数据的完整性。
7.2 FreeRTOS队列的使用
FreeRTOS队列在整个系统中起到了数据缓冲和任务间通信的重要作用。在UART中断处理中,队列
uart_rxq
用于存储接收到的数据,
uart_txq
用于存储待发送的数据。使用队列而非传统的内存数组缓冲区,具有以下优点:
-
线程安全
:FreeRTOS队列提供了线程安全的操作接口,多个任务可以安全地对队列进行读写操作,避免了数据竞争和不一致的问题。
-
阻塞机制
:队列的读写操作可以设置阻塞时间,当队列为空或已满时,任务可以选择阻塞等待,直到队列状态满足条件。这种机制使得任务的执行更加高效,避免了不必要的轮询。
-
灵活性
:队列可以存储不同类型的数据,并且可以根据需要动态调整队列的长度。
7.3 ISR不阻塞执行的原因
中断服务例程(ISR)必须保证不阻塞执行,这是因为ISR是在中断上下文中执行的,具有较高的优先级。如果ISR阻塞,会导致其他中断无法及时响应,从而影响系统的实时性和稳定性。例如,在
usart1_isr
函数中,使用
xQueueSendFromISR
函数将数据发送到队列时,该函数是专门为ISR设计的,能够在不阻塞的情况下完成数据的发送。如果使用普通的队列发送函数,可能会因为队列已满而导致ISR阻塞。
7.4
usart_send
与
usart_send_blocking
的选择
在
tx_task
函数中,使用
usart_send
函数而不是
usart_send_blocking
函数来发送数据。这是因为
usart_send_blocking
函数会一直等待UART外设准备好接收新数据,期间不会释放CPU资源,而
usart_send
函数在UART未准备好时会让出CPU控制权,使得其他任务可以继续执行。由于
libopencm3
库不知道我们正在使用FreeRTOS内核,
usart_send_blocking
函数没有实现任务调度的功能,因此在多任务环境下,使用
usart_send
函数能够更好地实现任务的并发执行。
8. 常见问题及解决方法
8.1 数据丢失问题
在高波特率下,由于没有启用流控制,可能会出现数据丢失的问题。解决方法如下:
-
降低波特率
:降低数据传输的波特率,减少数据发送的速度,使得接收器有足够的时间处理每一个数据。例如,将波特率从115200降低到9600。
-
启用硬件流控制
:STM32 USART设备和
libopencm3
库支持硬件流控制,通过配置相应的引脚和寄存器,可以实现数据传输的流量控制。当接收器处理不过来时,发送器会暂停发送数据,避免数据丢失。
8.2 编译和烧录问题
-
编译错误
:如果在编译过程中出现错误,首先检查代码的语法错误,特别是头文件的包含、函数调用和变量定义等方面。另外,确保
Makefile中的SRCFILES宏包含了所有需要编译的源文件。 -
烧录失败
:烧录失败可能是由于硬件连接问题、烧录工具版本不兼容等原因导致的。检查STM32与烧录器的连接是否正常,确保烧录工具(如
st-flash)的版本支持目标芯片的闪存容量。对于支持128K闪存的STM32F103C8T6芯片,使用make bigflash命令进行烧录。
9. 进一步学习建议
9.1 深入研究FreeRTOS
FreeRTOS是一个功能强大的实时操作系统内核,除了队列之外,还提供了任务管理、信号量、互斥锁等丰富的功能。可以深入学习FreeRTOS的官方文档和示例代码,了解其更多的特性和应用场景。例如,学习如何使用信号量来实现任务间的同步,如何使用互斥锁来保护共享资源。
9.2 探索硬件流控制
虽然本文没有详细介绍硬件流控制的实现,但它是解决数据丢失问题的有效方法。可以查阅STM32 USART设备和
libopencm3
库的相关文档,学习如何配置和使用硬件流控制。通过实际项目实践,掌握硬件流控制的原理和应用。
9.3 优化项目代码
在现有项目的基础上,可以对代码进行优化,提高系统的性能和稳定性。例如,优化中断服务例程的执行时间,减少中断处理的延迟;对队列的长度和任务的优先级进行合理调整,提高系统的并发处理能力。
表格:UART相关函数总结
| 函数名 | 功能 | 关键代码 |
|---|---|---|
usart1_isr
| UART中断服务例程,将接收到的数据存入队列 |
while ( ((USART_SR(USART1) & USART_SR_RXNE) != 0) ) { ch = usart_recv(USART1); xQueueSendFromISR(uart_rxq, &ch, &hptask); }
|
uart_getc
| 从队列中获取接收到的数据 |
while ( xQueueReceive(uart_rxq, &ch, 0) != pdPASS ) taskYIELD();
|
main_task
| 接收字符并发送回UART,可进行大小写转换 |
char ch = uart_getc(); #if INVERT_CASE if ( islower(ch) ) ch = toupper(ch); else if ( isupper(ch) ) ch = tolower(ch); #endif uart_putc(ch);
|
uart_putc
| 将字符发送到UART队列 |
while ( xQueueSend(uart_txq, &ch, 0) != pdPASS ) taskYIELD();
|
tx_task
| 从队列中取出字符并发送到UART |
while ( xQueueReceive(uart_txq, &ch, portMAX_DELAY) != pdPASS ) taskYIELD(); while ( !usart_get_flag(USART1, USART_SR_TXE) ) taskYIELD(); usart_send(USART1, ch);
|
流程图:UART数据处理流程
graph TD;
A[数据到达UART] --> B[触发中断];
B --> C[执行usart1_isr];
C --> D[将数据存入uart_rxq];
D --> E[main_task从uart_rxq获取数据];
E --> F[处理数据(可选大小写转换)];
F --> G[uart_putc将数据存入uart_txq];
G --> H[tx_task从uart_txq取出数据];
H --> I[发送数据到UART];
通过以上对STM32 UART中断处理和新项目创建的详细介绍,希望能够帮助读者更好地理解和掌握相关技术,在实际项目开发中灵活运用。同时,鼓励读者不断探索和学习,进一步提升自己的开发能力。
超级会员免费看
831

被折叠的 条评论
为什么被折叠?



