zoukankan      html  css  js  c++  java
  • 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] = '';
                // 将内容写回到串口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.
    "); 
            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);

    流程参照下图:

       

  • 相关阅读:
    《DSP using MATLAB》Problem 6.17
    一些老物件
    《DSP using MATLAB》Problem 6.16
    《DSP using MATLAB》Problem 6.15
    《DSP using MATLAB》Problem 6.14
    《DSP using MATLAB》Problem 6.13
    《DSP using MATLAB》Problem 6.12
    《DSP using MATLAB》Problem 6.11
    P1414 又是毕业季II
    Trie树
  • 原文地址:https://www.cnblogs.com/jiangzhaowei/p/10857888.html
Copyright © 2011-2022 走看看