硬汉嵌入式论坛

 找回密码
 立即注册
查看: 541|回复: 4
收起左侧

新手请教,STM32F429上的FreeRTOS,USART1串口可以写但读取有问题

[复制链接]

1

主题

1

回帖

4

积分

新手上路

积分
4
发表于 2023-7-25 16:02:31 | 显示全部楼层 |阅读模式

刚刚学习嵌入式,找了个STM32F429上的FreeRTOS的例子,可以通过USART1串口发送数据,在qemu模拟器上运行,COM3和COM4是一对虚拟串口,
qemu命令:qemu-system-gnuarmeclipse --verbose --board STM32F429I-Discovery --mcu STM32F429ZI -serial COM3 --image hello_rtos.elf --semihosting-config enable
putty连接COM4,可以看到写串口输出的AAAA……,一旦输入任何字符,写串口终止。
第一个问题:请问如何实现读和写串口。
第二个问题:采用半主机模式,但printf信息没有输出到串口。这个是怎么回事呢。
谢谢!

main.c如下:

[C] 纯文本查看 复制代码
#include "stm32f4xx.h"
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "stdio.h"

// 定义消息队列大小
#define QUEUE_LENGTH    10

// 消息数据结构
typedef struct
{
    uint8_t data;  // 字节数据
} MsgData;

// 声明一个消息队列句柄
QueueHandle_t xQueue;

// USART发送任务
void USART_SendTask(void *pvParameters)
{
    MsgData msg;
    msg.data = 'A';

    while(1)
    {
        // 发送字节 'A'
        while(!(USART1->SR & USART_SR_TXE)); // 等待发送缓冲区为空
        USART1->DR = msg.data;

        xQueueReceive(xQueue, &msg, 0); // 尝试接收消息,等待时间为0

        vTaskDelay(pdMS_TO_TICKS(1000)); // 延时1秒
    }
}


// USART接收任务
void USART_ReceiveTask(void *pvParameters)
{
    MsgData msg;

    while(1)
    {
        if (USART1->SR & USART_SR_RXNE) // 检查接收缓冲区是否非空
        {
            uint8_t data = USART1->DR; // 读取接收到的字节

            //if (data == 'B')
            {
                // 执行接收到的指令
                // 例如,打印一条消息
//printf("Received 'B'\n");

                // 发送消息给发送任务
                msg.data = 'B';
                xQueueSend(xQueue, &msg, 0);
            }
        }

        vTaskDelay(pdMS_TO_TICKS(100)); // 延时100毫秒
    }
}

int main(void)
{
    // 初始化硬件
    
    // 创建一个消息队列
    xQueue = xQueueCreate(QUEUE_LENGTH, sizeof(MsgData));

    // 使能USART1和GPIOA的时钟
    RCC->APB2ENR |= RCC_APB2ENR_USART1EN;
    RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;

    // 配置 GPIOA 的引脚 PA9 为复用推挽输出模式(TX)
    // 配置 GPIOA 的引脚 PA10 为浮空输入模式(RX)
    GPIOA->MODER |= GPIO_MODER_MODER9_1 | GPIO_MODER_MODER10_0;
    GPIOA->OTYPER &= ~GPIO_OTYPER_OT_9;
    GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR9;  // 设置引脚速度为高速
    GPIOA->PUPDR &= ~GPIO_PUPDR_PUPDR9;
    GPIOA->PUPDR |= GPIO_PUPDR_PUPDR10_0;

    // 配置 USART1
    USART1->CR1 &= ~USART_CR1_UE; // 禁用 USART1
    USART1->CR1 &= ~USART_CR1_M; // 8 位数据位(字长)
    USART1->CR2 &= ~USART_CR2_STOP; // 1 位停止位
    USART1->CR1 &= ~USART_CR1_PCE; // 无校验
    USART1->CR1 &= ~USART_CR1_OVER8; // Oversampling 16
    USART1->BRR = 0x1D4C; // 波特率 9600 @ 16MHz
    USART1->CR1 |= USART_CR1_TE; // 使能发送
    USART1->CR1 |= USART_CR1_RE; // 使能接收
    USART1->CR1 |= USART_CR1_UE; // 使能 USART1

    // 配置 USART1 的接收中断
    NVIC_SetPriority(USART1_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY);
    NVIC_EnableIRQ(USART1_IRQn);
    USART1->CR1 |= USART_CR1_RXNEIE;

    // 创建发送任务
    xTaskCreate(USART_SendTask, "USART_SendTask", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL);

    // 创建接收任务
    xTaskCreate(USART_ReceiveTask, "USART_ReceiveTask", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL);

    // 启动任务调度器
    vTaskStartScheduler();

    while (1)
    {
        // 此处添加程序逻辑
    }
}
void vApplicationStackOverflowHook(TaskHandle_t xTask,
                                   char *pcTaskName)
{
    // 空实现,可以在此处添加堆栈溢出时的处理逻辑
}

void vApplicationMallocFailedHook(void)
{
    // 空实现,可以在此处添加内存分配失败时的处理逻辑
}

void vApplicationTickHook(void)
{
    // 空实现,可以在此处添加每个时钟节拍(tick)时的处理逻辑
}

void vApplicationIdleHook(void)
{
    // 空实现,可以在此处添加空闲任务处理逻辑
}



Makefile内容如下:
[C] 纯文本查看 复制代码
# GNU ARM Embedded Toolchain
CC=arm-none-eabi-gcc
LD=arm-none-eabi-ld
AR=arm-none-eabi-ar
AS=arm-none-eabi-as
CP=arm-none-eabi-objcopy
OD=arm-none-eabi-objdump

# Build Parameters: MCU Flags, Definitions, Includes, 
#                   Compile Flags, Linker Script, Linker Flags
MCFLAGS=-mcpu=cortex-m4 -mthumb -mlittle-endian \
-mfpu=fpv4-sp-d16 -mfloat-abi=hard -mthumb-interwork
DEFS=-DUSE_STDPERIPH_DRIVER -DSTM32F4XX
INCLUDES=-I. \
-I../../Libraries/CMSIS/Device/ST/STM32F4xx/Include \
-I../../Utilities/STM32F429I-Discovery \
-I../../Libraries/CMSIS/Include \
-I../../Libraries/STM32F4xx_StdPeriph_Driver/inc \
-I../../FreeRTOS/Source/portable/GCC/ARM_CM3 \
-I../../FreeRTOS/Source/include \
-I../../TraceRecorder/include
CFLAGS=-c $(MCFLAGS) $(DEFS) $(INCLUDES)
LDSCRIPT = ./stm32_flash.ld
LDFLAGS=-T $(LDSCRIPT) --specs=nosys.specs $(MCFLAGS)

# Inputs: C Sources, Assembler Sources
SOURCES=main.c stm32f4xx_it.c system_stm32f4xx.c \
../../Utilities/STM32F429I-Discovery/stm32f429i_discovery.c \
../../Libraries/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_syscfg.c \
../../Libraries/STM32F4xx_StdPeriph_Driver/src/misc.c \
../../Libraries/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_gpio.c \
../../Libraries/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_rcc.c \
../../Libraries/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_exti.c \
../../Libraries/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_i2c.c \
../../Libraries/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_dma.c \
../../Libraries/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_usart.c \
../../FreeRTOS/Source/portable/GCC/ARM_CM3/port.c \
../../FreeRTOS/Source/portable/MemMang/heap_2.c \
../../FreeRTOS/Source/croutine.c \
../../FreeRTOS/Source/event_groups.c \
../../FreeRTOS/Source/list.c \
../../FreeRTOS/Source/queue.c \
../../FreeRTOS/Source/tasks.c \
../../FreeRTOS/Source/timers.c \
../../TraceRecorder/trcKernelPort.c \
../../TraceRecorder/trcSnapshotRecorder.c \
../../TraceRecorder/trcStreamingRecorder.c
ASMSOURCES=../../Libraries/CMSIS/Device/ST/STM32F4xx/Source/Templates/gcc_ride7/startup_stm32f429_439xx.s

# Outputs: Object Files, ELF Executable & 
#          Converted ELF Executable to Intel HEX format
OBJECTS=$(SOURCES:%.c=%.o)
OBJECTS+=$(ASMSOURCES:%.s=%.o)
EXECUTABLE=hello_rtos.elf
TARGET=hello_rtos.hex

# Build Rules
.PHONY: release
release: $(TARGET)

.PHONY: all
all: $(TARGET)

.PHONY: debug
debug: CFLAGS+=-g # Add debug flag
debug: LDFLAGS+=-g
debug: $(TARGET) 

$(TARGET): $(EXECUTABLE)
	$(CP) -O ihex $< $@
	@echo "Objcopy from ELF to IHEX complete!\n"

$(EXECUTABLE): $(OBJECTS)
	$(CC) $(LDFLAGS) $(OBJECTS) -o $@
	@echo "Linking complete!\n"

%.o: %.c
	$(CC) $(CFLAGS) $< -o $@
	@echo "Compiled "$<"!\n"

%.o: %.s
	$(CC) $(CFLAGS) $< -o $@
	@echo "Assambled "$<"!\n"

.PHONY: clean
clean:
	rm -f $(OBJECTS) $(EXECUTABLE) $(TARGET)

回复

使用道具 举报

6

主题

637

回帖

655

积分

金牌会员

积分
655
QQ
发表于 2023-7-25 20:20:53 | 显示全部楼层
手撸寄存器,是一个狠人
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106749
QQ
发表于 2023-7-26 06:39:27 | 显示全部楼层
1、改成一个任务,串口自发自收,即简单的回环,看看正常不。
2、QEMU没玩过,实际板子上测试的话,以MDK或者IAR为例,需要关闭半主模式,重定向底层接口到硬件串口来实现printf。
回复

使用道具 举报

1

主题

1

回帖

4

积分

新手上路

积分
4
 楼主| 发表于 2023-7-28 12:30:50 | 显示全部楼层
通过GDB调试,在USART_ReceiveTask函数的下面这句话打断点,不通过putty按键,可以每隔一段时间进来。按键之后再也没有进断点。貌似不应该把发送功能写到任务里,应该做一个中断服务?
        if (USART1->SR & USART_SR_RXNE)
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106749
QQ
发表于 2023-7-28 15:03:28 | 显示全部楼层
jeoky 发表于 2023-7-28 12:30
通过GDB调试,在USART_ReceiveTask函数的下面这句话打断点,不通过putty按键,可以每隔一段时间进来。按键 ...

接收用中断,实时性好。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-5-4 08:43 , Processed in 0.253033 second(s), 26 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表