STM32 + RT Thread OS 串口通讯

1.   创建项目

a)   禁用Finsh和console

b)   默认情况下,项目文件包含了finsh,它使用COM1来通讯,另外,console输出(rt_kprintf)也使用了COM1。因此,在运行scons命令生成项目文件之前,修改rtconfig.h,禁用这两项。(下图L65, L70)

  

c)   生成项目文件

运行scons --target=mdk4 –s

打开生成的项目文件,可以看到,文件组finsh已经不再被包含进来了。

d)   创建echo.c

新建一个C文件echo.c,编写RT_Thread任务入口,COM1侦听,以及初始化函数。示例代码如下:

#include "echo.h"

struct rx_msg
{
    rt_device_t dev;
    rt_size_t   size;
};

static struct rt_messagequeue  rx_mq;
static char uart_rx_buffer[64];
static char msg_pool[2048];

// 串口侦听回调函数
rt_err_t uart_input(rt_device_t dev, rt_size_t size)
{
    struct rx_msg msg;
    msg.dev = dev;
    msg.size = size;

        // 将接收内容放入消息队列
    rt_mq_send(&rx_mq, &msg, sizeof(struct rx_msg));

    return RT_EOK;
}

// 任务入口函数
void usr_echo_thread_entry(void* parameter)
{
    struct rx_msg msg;

    rt_device_t device;
    rt_err_t result = RT_EOK;

        // 从RT系统中获取串口1设备
    device = rt_device_find("uart1");
    if (device != RT_NULL)
    {
                           // 指定接收串口内容的回调函数
        rt_device_set_rx_indicate(device, uart_input);
                           // 以读写方式打开设备
        rt_device_open(device, RT_DEVICE_OFLAG_RDWR);
    }

    while(1)
    {
                           // 从消息队列中获取被回调函数放入消息队列中的内容
        result = rt_mq_recv(&rx_mq, &msg, sizeof(struct rx_msg), 50);
        if (result == -RT_ETIMEOUT)
        {
            // timeout, do nothing
        }

        if (result == RT_EOK)
        {
            rt_uint32_t rx_length;

            rx_length = (sizeof(uart_rx_buffer) - 1) > msg.size ?
                msg.size : sizeof(uart_rx_buffer) - 1;

            rx_length = rt_device_read(msg.dev, 0, &uart_rx_buffer[0], rx_length);
            uart_rx_buffer[rx_length] = ‘\0‘;
            // 将内容写回到串口1
            rt_device_write(device, 0, &uart_rx_buffer[0], rx_length);
        }
    }
}
// 串口例程初始化函数
void usr_echo_init()
{
    rt_thread_t thread ;

    rt_err_t result;
      // 创建消息队列,分配队列存储空间
    result = rt_mq_init(&rx_mq, "mqt", &msg_pool[0], 128 - sizeof(void*), sizeof(msg_pool), RT_IPC_FLAG_FIFO);

    if (result != RT_EOK)
    {
        rt_kprintf("init message queue failed.\n");
        return;
    }
    // 创建任务线程
    thread = rt_thread_create("devt",
        usr_echo_thread_entry, RT_NULL,
        1024, 25, 7);
    // 启动任务线程
    if (thread != RT_NULL)
        rt_thread_startup(thread);
}

在application.c中加入初始化代码(echo.h略)
L189:usr_echo_init()

  

在开始编译前,还要修改board.c,注释掉第183行,不然将报错。因为我们禁用了console,所以不需要设置console输出设备。

  

3.   程序分析

a)   内存分布

查看编译生成的 obj/rtthread-stm32.map文件,可以看到代码及常量,被下载到芯片的0x8000000地址段,最前面的是中断矢量表,第一个中断地址是RESET,矢量表共0x130个字节。

  

有初始值的变量定义,从地址段0x20000000开始

  

对应的Stm32内存映射表,代码和常量被下载到Flash,已初始化变量定位到SRAM(可能是下载到Flash,开机初始化后复制到RAM,而不是直接下载到RAM,不然下次运行,初始值可能已被修改)

  

这是MDK中芯片内存区域的地址分配

  

这是J-Link对芯片的定义,内存是512K,类型是On-chip Flash,地址空间从0x08000000到0x0807FFFF

  

b)   程序运行流程

开机后,从Flash 0x080000000处的中断矢量表,取得RESET中断的处理函数入口地址,跳转到入口函数开始执行RESET中断服务,如下图,RESET中断服务函数定义在startup_stm32f10x_hd.s中,先执行了stm32类库中的SystemInit(),再然后转到main()函数。

  

SystemInit()主要是对芯片的基本设置,如时钟频率。

RT-Thread中,在BSP目录下提供了startup.c,包含了main()函数,它调用了同文件中的rtthread_startup(),再然后rtthread_startup()调用了rt_application_init(),rt_application_init()则在application.c中定义,用户代码就从这里开始。

另外还有一个重要文件是stm32f10x_it.c,这里面定义了中断服务例程,中断矢量表中的地址指向这个文件中相应的服务函数入口地址。比如,我们的串口1收到上位机的消息后,会产生USART1_IRQ,这时芯片就会在0x08000000开始的中断向量表中找到USART1_IRQHandler()的入口地址,跳转后开始执行中断服务函数USART1_IRQHandler()。

  

当然,要产生中断,需要在初始化代码中开启中断。

<echo.c>

上面贴出了这个文件的源代码,除了uart_input(),其它都比较直观。在RTT系统中,uart_input()只是USART1_IRQHandler()的一部分,在echo.c的初始化代码中,被注册为uart1这个device(RTT封装对象)的回调函数:

L34:rt_device_set_rx_indicate(device, uart_input);

流程参照下图:

  

原文地址:https://www.cnblogs.com/jiangzhaowei/p/10857888.html

时间: 2024-10-13 14:55:48

STM32 + RT Thread OS 串口通讯的相关文章

STM32调试大法 之 串口通讯

开发过程经常需要查看某些特定参数.通常的方法可以使用paintf进行打印输出,观察具体的变量值.STM32内部集成有USART的串口功能,可以通过串口直接输出到电脑(上位机).使用非常方便,基本不需要不需要写代码,只要配置一下就可以使用. 简单设置就可以看到上面的效果 配置方法: 1.重定向printf的输出函数 int fputc(int ch, FILE *f) 2.配置STM32F10x的USART串口 重定向方法 stdio.h 的输出内容 int fputc(int ch, FILE

STM32与PC机串口通讯

有时要将板子的信息输出到电脑上来调试之类的,或者把传感器收集到的数据显示到电脑. 当然了,这只是最基本的串口通信,简单的说,是有一根USB线连着的. mbed上并没有能显示printf的功能.需要自己配置一下.我用的是win8,只讲一下win8了. 1.在官网下载板子的驱动程序. 2.win8没有超级终端,自己下一个.这里推荐Tera Term.下载地址 http://osdn.jp/projects/ttssh2/downloads/64118/teraterm-4.89.exe/ 这两步都是

RT Thread学习历程(1):串口乱码问题

因为学习实时系统,最近接触到RT Thread. 把RT Thread官网上的示例代码烧录到STM32的板子上之后,在串口软件上接收到的全是乱码,一开始以为是串口软件的问题,换了2个软件之后情况都一样,最后发现是晶振的问题,我用的是STM32F407VGT6,晶振要设为8MHz,代码相应的设置晶振的部分也要修改.

串口通讯的代码 。是别人写的 我加了些注释。

// Communication.h: interface for the CCommunication class. // ////////////////////////////////////////////////////////////////////// #if !defined(AFX_COMMUNICATION_H__6CA00576_F088_11D1_89BB_8311A0F2733D__INCLUDED_) #define AFX_COMMUNICATION_H__6CA0

Winform 串口通讯之地磅

继上次的读卡之后,要做一个地磅的读取. 下面是我在读卡Demo上改的读取地磅的. 地磅是一直向串口发送数据的,所以需要截取数据来一直判断数据是否合法,然后计算出结果. 其中遇到了一个小问题,文末有介绍. 本人初学菜鸟,大牛们有意见欢迎评论. 1 using System; 2 using System.Collections.Generic; 3 using System.ComponentModel; 4 using System.Data; 5 using System.Drawing; 6

HALCON串口通讯程序

串口通讯程序 * Note: This example is meant to demonstrate the use of the serial interface * of HALCON.  On Unix machines, the output and input is from /dev/tty, i.e., the * window from which you have started HDevelop.  On Windows NT machines, * this progra

串口通讯服务类

通讯事件类 public class ComEvent { /// <summary> /// 数据接收事件 /// </summary> /// <param name="sender"></param> /// <param name="data"></param> public delegate void DataReceivedHandler(object sender, string

C#串口通讯

本文提供一个用C#实现串口通讯实例,亲自编写,亲测可用! 开发环境:VS2008+.net FrameWork3.5(实际上2.0应该也可以) 第一步 创建一个WinForm窗体,拉入一些界面元素 重点就是,图中用红框标出的,工具箱——组件——SerialPort,做.net串口通讯,这是必备控件 第二步 设置SerialPort控件属性 用C#向串口发送数据没什么特别的,就是调用SerialPort的Write方法往串口写数据就行 但是从串口那里接收数据的方式就比较特别了 首先,需要在代码里声

串口通讯编程

本代码参考  网络通信程序设计<张晓明 编著>,在此记下方便自己以后查询 1.以下窗口为串口设置页面代码 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System