wuyage

MQX之UART使用

0
阅读(2591)

串口最常用的两个功能就是查询方式发送数据和中断方式接收数据。
在MQX该如何实现呢?
以FRDM_K64f +Freescale_MQX_4_1_FRDMK64F 为例来说明。
实现的功能是:
1)UART0 用作printf
2)UART1 实现查询发送和中断接收
中断接收的过程我采用的方法是:在MQX uart驱动的基础上增加callback函数,在callback函数中通过lwsem手段通知另外一个读串口数据的任务

UART1使用的是PTC3和PTC4,开发板上的接口如下:
这里写图片描述

实现步骤如下:
1)user_config.h 中

#define BSPCFG_ENABLE_TTYB       1   // wenxue 0->1 
#define BSPCFG_ENABLE_ITTYB      1  // wenxue 0->1

2)在 serinprv.h 中增加一个回调函数
先声明

typedef void (_CODE_PTR_  UART_NOTIFICATION_FPTR)(void *); // wenxue 2015-10-12

在io_serial_int_device_struct  这个结构中加入

/* UART Notification Callback wenxue 2015-10-12 */
UART_NOTIFICATION_FPTR DEV_RX_TX_CALLBACK;

3)serl_int_kuart.c 中的_kuart_int_rx_tx_isr 函数中加入回调函数的调用

if (stat & UART_S1_RDRF_MASK) {      
// reading 'D' register performs also cleanup of 'S1'
      c = sci_ptr->D;      
      if (!_io_serial_int_addc(int_io_dev_ptr, c)) {
          sci_info_ptr->RX_DROPPED_INPUT++;
      }
      sci_info_ptr->RX_CHARS++;      
      /* call UART CALL Back function if installed  wenxue         2015-10-12*/
      if(int_io_dev_ptr->DEV_RX_TX_CALLBACK != NULL)
           int_io_dev_ptr->DEV_RX_TX_CALLBACK(int_io_dev_ptr);
   }

4)serl_int.c和serial.h 增加ioctl 安装回调函数的支持
_io_serial_int_ioctl 中

 /* add IO_IOCTL_SERIAL_SET_RXTX_CALLBACK wenxue 2015-10-12 */    
     case IO_IOCTL_SERIAL_SET_RXTX_CALLBACK:
         int_io_dev_ptr->DEV_RX_TX_CALLBACK = (UART_NOTIFICATION_FPTR)param_ptr;         
         break;
#define IO_IOCTL_SERIAL_SET_RXTX_CALLBACK      _IO(IO_TYPE_SERIAL, 0x1F)

以上修改完成后,重新编译bsp工程

5)在原hello 工程中做修改,完成应用程序

/*HEADER**********************************************************************
*
* Copyright 2008 Freescale Semiconductor, Inc.
* Copyright 1989-2008 ARC International
*
* This software is owned or controlled by Freescale Semiconductor.
* Use of this software is governed by the Freescale MQX RTOS License
* distributed with this Material.
* See the MQX_RTOS_LICENSE file distributed for more details.
*
* Brief License Summary:
* This software is provided in source form for you to use free of charge,
* but it is not open source software. You are allowed to use this software
* but you cannot redistribute it or derivative works of it in source form.
* The software may be used only in connection with a product containing
* a Freescale microprocessor, microcontroller, or digital signal processor.
* See license agreement file for full license terms including other
* restrictions.
*****************************************************************************
*
* Comments:
*
*   This file contains the source for the hello example program.
*
*
*END************************************************************************/



#include #include  
#include #if ! BSPCFG_ENABLE_IO_SUBSYSTEM
#error This application requires BSPCFG_ENABLE_IO_SUBSYSTEM defined non-zero in user_config.h. Please recompile BSP with this option.
#endif


#ifndef BSP_DEFAULT_IO_CHANNEL_DEFINED
#error This application requires BSP_DEFAULT_IO_CHANNEL to be not NULL. Please set corresponding BSPCFG_ENABLE_TTYx to non-zero in user_config.h and recompile BSP with this option.
#endif


/* Task IDs */
#define HELLO_TASK 5
#define READ_TASK    6

extern void hello_task(uint32_t);
extern void read_task(uint32_t initial_data);

MQX_FILE_PTR uart1_int_dev = NULL;

void uart1_rx_callback(void *param);

LWSEM_STRUCT   uart1_frame_received; // wenxue

const TASK_TEMPLATE_STRUCT  MQX_template_list[] = 
{ 
    /* Task Index,   Function,   Stack,  Priority, Name,     Attributes,          Param, Time Slice */
    { HELLO_TASK,   hello_task, 1500,   8,        "hello",  MQX_AUTO_START_TASK, 0,     0 },
    { READ_TASK,    read_task,  1000,   8,          "read",     MQX_AUTO_START_TASK, 0,     0 }, // added by wenxue
    { 0 }
};


/*TASK*-----------------------------------------------------
* 
* Task Name    : hello_task
* Comments     :
*    This task prints " Hello World "
*
*END*-----------------------------------------------------*/
void hello_task
    (
        uint32_t initial_data
    )
{  
   (void)initial_data; /* disable 'unused variable' warning */
    uint32_t result;
    MQX_FILE_PTR uart1_dev = NULL;
    int buad = 115200;
    char data_buffer[]="I Love Beijing\r\n";
    
    printf("Hello World\n");  // uart0 
    
    uart1_dev=fopen( "ttyb:", NULL);
   	
    if( uart1_dev == NULL )
    {
      /* device could noFt be opened */
      _task_block();
    }
    
    /* Set baud as 115200 */
    result = ioctl(uart1_dev,IO_IOCTL_SERIAL_SET_BAUD,&buad);
 
   if( result == IO_ERROR_INVALID_IOCTL_CMD )
   {
      /* ioctl not supported, use newer MQX version */
      _task_block();
   }
   
   /* send data to uart */
   write( uart1_dev, data_buffer, strlen(data_buffer));
   
   /* wait for transfer complete flag */
   result = ioctl( uart1_dev, IO_IOCTL_SERIAL_WAIT_FOR_TC, NULL );
   if( result == IO_ERROR_INVALID_IOCTL_CMD )
   {
      /* ioctl not supported, use newer MQX version */
      _task_block();
   }
   
   fclose(uart1_dev);
   
   
   
 //  uart1_int_dev=fopen( "ittyb:", NULL);
   uart1_int_dev=fopen( "ittyb:", (char const *) IO_SERIAL_NON_BLOCKING);
   
   if( uart1_dev == NULL )
    {
      /* device could not be opened */
      _task_block();
   }
   
  result = ioctl( uart1_int_dev, IO_IOCTL_SERIAL_SET_RXTX_CALLBACK, (void*)uart1_rx_callback ); 
  
  if( result == IO_ERROR_INVALID_IOCTL_CMD )
   {
      /* ioctl not supported, use newer MQX version */
      _task_block();
   }
 
   /* Create the lightweight semaphores */
   result = _lwsem_create(&uart1_frame_received, 0);
   if (result != MQX_OK) {
      printf("\nCreating read_sem failed: 0x%X", result);
      _task_block();
   }
   
  /* Has already called _int_install_isr(sci_init_ptr->RX_TX_VECTOR, _kuart_int_rx_tx_isr, int_io_dev_ptr); wenxue*/
  //_int_install_isr(INT_UART1_RX_TX, UART1_RX_ISR,NULL); 
	
   _task_block();
    
}


void uart1_rx_callback(void *param)
{
   _lwsem_post(&uart1_frame_received); 
}
		 

/*TASK*--------------------------------------------------------
*
* Task Name : read_task
* Comments  : This task used to read uart data
*            
*END*--------------------------------------------------------*/

void read_task 
   (
      uint32_t initial_data
   )
{
   uint32_t  bytesRead; 
   int num=0;
   char data_buffer[100];
   
   printf("\n read task created: 0x%lX", initial_data);
   while (TRUE) {
      if (_lwsem_wait(&uart1_frame_received) != MQX_OK) {
         printf("\n_lwsem_wait failed");
         _task_block();
      }
   /* read  data */    
   bytesRead= fread(data_buffer, 1, 20, uart1_int_dev);  
   
   /* write data */ 
   fwrite(data_buffer,1,bytesRead,uart1_int_dev);
   }
}
/* EOF */

另外需要说明的是: 

uart1_int_dev=fopen( "ittyb:", NULL);打开方式是默认的blocking 方式

bytesRead= fread(data_buffer, 1, 20, uart1_int_dev);如果通过fread 读取多字节数据,如果串口没有接收到20字节数据,那么会阻塞在这里,直到读取20字节完成才往下执行。 

也可以uart1_int_dev=fopen( “ittyb:”, (char const *) IO_SERIAL_NON_BLOCKING); 以Non blocking方式打开,这时fread可以立刻返回。此时任务的执行过程是:每次接收到1个字节数据,进中断,释放信号量,read task 等到信号量然后通过fread读出,最后fwrite发送出去。所以尽管fread的参数是20,但其实每次都是读到1字节。

实验现象是: 
UART1 先输出 I Love Beijing 
在UART1 接收到一串字符后,通过UART1再输出。