jeoky 发表于 2023-7-25 16:02:31

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


刚刚学习嵌入式,找了个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如下:

#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内容如下:
# 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)

yklstudent 发表于 2023-7-25 20:20:53

手撸寄存器,是一个狠人

eric2013 发表于 2023-7-26 06:39:27

1、改成一个任务,串口自发自收,即简单的回环,看看正常不。
2、QEMU没玩过,实际板子上测试的话,以MDK或者IAR为例,需要关闭半主模式,重定向底层接口到硬件串口来实现printf。

jeoky 发表于 2023-7-28 12:30:50

通过GDB调试,在USART_ReceiveTask函数的下面这句话打断点,不通过putty按键,可以每隔一段时间进来。按键之后再也没有进断点。貌似不应该把发送功能写到任务里,应该做一个中断服务?
      if (USART1->SR & USART_SR_RXNE)

eric2013 发表于 2023-7-28 15:03:28

jeoky 发表于 2023-7-28 12:30
通过GDB调试,在USART_ReceiveTask函数的下面这句话打断点,不通过putty按键,可以每隔一段时间进来。按键 ...

接收用中断,实时性好。
页: [1]
查看完整版本: 新手请教,STM32F429上的FreeRTOS,USART1串口可以写但读取有问题