代码生成器配置和软件UART的实现

描述

 

由于MCU内部资源限制,在应用中会出现UART接口不够用的情况,如果UART使用的波特率不太高,而且系统中的负荷不是很大的情况就可以使用端口来模拟UART的收发,下文是一个在R5F100LE(RL78)上的具体的实现方法,这里略去工程的建立过程,相应的驱动程序细节可以参考代码生成器生成的代码,这里只重点讲述代码生成器配置和软件UART的实现。

一、硬件资源准备

01一个具有外部边沿中断功能的IO口来做UART的RXD端口,下面是一个配置的例子,在这里我们使用P137(INTP0),在代码生成器里选择INTP0为下降沿中断,中断优先级可以任意设置。

代码生成器

02一个普通的输出口来作为UART的TXD端口。这里选择P43端口,设置端口输出高。

代码生成器

03两个可以产生中断、可以随时关闭启动、定时间隔可以任意设定的定时器,一个发送定时器用于发送数据,一个接收定时器用于接收数据。

将接收定时器的定时间隔初始化为1位数据的时长的一半,比如波特率2400,1位为416.6us,那么定时器设置为416.6us/2=208.3us,在这里我们使用了Timer的Channel 1

代码生成器代码生成器

将发送定时器的定时间隔设置为1位数据时长,比如波特率2400,1位为416.6us,那么定时器设置为416.6us,在这里我们使用Timer的Channel 0。

代码生成器

二、UART接收功能的实现

01接收的软件实现

接收时我们需要写两个中断函数,在中断里完成数据的接收,接收完毕后设置一个标志,在主循环中根据标志来判断数据是否接收完毕。初始化时需要打开边沿中断,关闭定时器中断。

1)边沿中断函数处理

当下降沿中断到来时,在边沿中断函数里启动接收定时器,关闭边沿中断。具体程序如下:

左右滑动查看完整内容

 

void softuart_rece_port_fall_edge_callback(void)
{
  softuart_rece_state = 0;//接收定时器进入次数计数清零
  uart_port_intp_stop();// 关闭边沿中断
  start_uart_rece_timer();//打开接收定时器中断
}

 

这个函数放到r_cg_intc_user.c内

代码生成器

2)接收定时器中断函数

每奇数次进入中断时(第1,3,5…)进行RXD端口的采样并保存数据,同时根据我们的要求进行移位操作(比如LSB或MSB,数据长度是几位),在偶数次进入中断时就直接退出,当数据接收完成后设置标志,同时关闭接收定时器中断,打开边沿中断中断,具体程序如下,这里我是用的8位数据长度和1个停止位:

左右滑动查看完整内容

 

void softuart_rece_timer_callback(void)
{
static __saddr uint8_t uartrece_shift_reg;
  softuart_rece_state++;//进入次数++
  if(softuart_rece_state==1)//接收start位
  {
    //check start bit
    if(1==get_uart_rece_port())
    {
      //start bit error
      uartrece_shift_reg = 0;
      stop_uart_rece_timer();
      uart_port_intp_start();
    }
  }
  else if (softuart_rece_state<=17)//接收8位数据位
  {
    //receive data sampling point 3,5,7,9,11,13,15,17
    if(0==(softuart_rece_state&1)) return;
   uartrece_shift_reg >>= 1;
    if(1==get_uart_rece_port())
    {
      uartrece_shift_reg |= 0x80;
    }
  }
  else if(softuart_rece_state>=19)//接收停止位
  {
    //stop bit sample sampling point 19
    stop_uart_rece_timer();//关闭接收定时器
    uart_port_intp_start();//打开下降沿中断
    if(uartrece_end_fg ==0)
    {
      uartrece_data = uartrece_shift_reg;
      uartrece_end_fg =1;//设置接收完毕标志
    }
  }
}

 

这个程序要放到r_cg_timer_user.c内

代码生成器

3)在主循环里调用如下函数来判断是否收到数据

左右滑动查看完整内容

 

uint8_t get_softuart_rece(uint8_t * buff)
{
  if(uartrece_end_fg==1)
  {
    uartrece_end_fg =0;
    *buff = uartrece_data;//将数据放入接收缓冲区
    return 1;//说明收到数据
  }
  return 0;
}

 

三、UART发送功能的实现

01发送软件的实现

发送时需要写一个发送定时器中断函数,在中断里完成数据发送,发送完成后设置一个标志,在主循环中判断,初始化时需要关闭发送定时器,中断的代码如下:

左右滑动查看完整内容

 

void softuart_send_callback(void)
{
  softuart_send_state++;
  if(softuart_send_state==10)//发送停止位
  {
    //sampling point 10 stop bit
    softuart_send_port_h();
  }
  else if(softuart_send_state>10)//等待停止位发送完毕
  {
    //>11 stop bit send finished
    softuart_send_state=0;
    stop_uart_send_timer();
  }
  else//发送数据
  {
    //samplimng point 2,3,4,5,6,7,8,9
    if(0!=(uartsend_shift_reg&1))
    {
      softuart_send_port_h();
    }
    else
    {
      softuart_send_port_l();
    }
    uartsend_shift_reg >>= 1;
  }
}

 

这个程序要放到r_cg_timer_user.c内

代码生成器

当需要发送时,先将发送端口设置为低电平,然后开启发送定时器,如果正在发送返回发送错误。具体的操作代码如下:

左右滑动查看完整内容

 

uint8_t softuart_send(uint8_t data)
{
  if(softuart_send_state!=0)return 0;//数据没有发送完毕
  softuart_send_state = 1;
  DI();
  softuart_send_port_l();     //发送起始位
  uartsend_shift_reg=data;//将要发送的数据放到移位寄存器
  start_uart_send_timer();//启动UART发送定时器
  EI();
  return 1;
}

 

四、整个程序的初始化

由于相应硬件的初始化程序在R_Systeminit已经调用过了,所以我们只用调用启动程序就行了,为了方便程序的修改,用宏定义重新定义了接口部分。

左右滑动查看完整内容

 

#define start_uart_rece_timer() R_TAU0_Channel1_Start()
#define stop_uar_rece_timer()  R_TAU0_Channel1_Stop()
#define uart_port_intp_start()        R_INTC0_Start()
#define uart_port_intp_stop()        R_INTC0_Stop()
#define get_uart_rece_port()        P13_bit.no7
#define start_uart_send_timer() R_TAU0_Channel0_Start()
#define stop_uart_send_timer()  R_TAU0_Channel0_Stop()
#define softuart_send_port_h()        {P4_bit.no3 = 1;}
#define softuart_send_port_l()        {P4_bit.no3 = 0;}

 

如果想要修改使用的硬件资源只用修改宏定义即可。

在使用软件UART之前需要先调用一下如下初始化函数。

左右滑动查看完整内容

 

void softuart_int(void)
{
  stop_uart_send_timer();//停止发送定时器
  stop_uart_rece_timer();//停止接收定时器
  uart_port_intp_stop();  // 边沿中断接收停止
  softuart_send_port_h(); // TXD端口设置为高
  uart_port_intp_start();  // 允许RXD端口的下降沿中断
  softuart_send_state = 0;
  softuart_rece_state = 0;
  uartrece_end_fg = 0;
}

 

注意

 

1)使用上述方法就可以实现一个软件的UART操作,但是使用过程中不能有长时间的关闭中断操作,如果有的话会影响程序的执行。

2)如果通讯波特率发生变化需要修改定时器的定时值。

审核编辑:汤梓红

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分