目录

参考了沁恒官网22年1月更新的CH583EVT包中的UART1例程

功能:上位机通过串口1发送指令规定串口2和3的波特率,实现串口2和3之间的数据透传

担心串口3的接收中断会被串口2的发送中断打断而导致错误,故不采用在串口3的接收中断中,立即于串口2转发的方式(即串口3的中断服务函数中注释掉的两句),而采用缓存串口3接收的数据,在主函数中转发的方式。

实测串口2和3全部采用中断收发不缓存数据,不会影响串口透传。全部用中断收发,可以减小串口3的缓存,但是在中断使用较多的情况下可能会出问题。代码相似度很高,就不贴了。

#include "CH58x_common.h"

uint8_t RxBuff1[50];
uint8_t u1_i = 0; //用于判断字符长度
uint8_t RxBuff2[50];
uint8_t RxBuff3[100]; //串口3的接收缓存,串口2向串口3透传的数据不能溢出该数组
uint8_t trigB = 4; //FIFO的触发字节数,可以设置00b,01b,10b,11b。本程序中用了10b,这里直接赋了4
uint8_t RxBuff1_get = 0; //判断串口1是否接收完了一串字符,在串口1中断中的FIFO超时判断中置1
uint8_t u3_get_flag = 0; //判断串口3是否接收完一串字符串,在串口3中断中的FIFO超时判断中置1
uint8_t baud_get = 0; //判断是否接收到了串口1收到的波特率信息,格式 baud:XXXXX (9600/57600/115200等)
uint8_t u1_get[13] = {}; //接收存放串口1收到的波特率信息,方便仿真观察
uint8_t u3_i = 0; //记录串口3接收到的字节数,以便后续转发
uint32_t baud_num = 0; //存放波特率,用于初始化u2u3的函数 void u1_init()
{
  uint32_t x;   /* 配置串口1:先配置IO口模式,再配置串口 */
  GPIOA_SetBits(GPIO_Pin_9); //先将PA9置位为高
  GPIOA_ModeCfg(GPIO_Pin_8, GPIO_ModeIN_PU); // RXD-配置上拉输入
  GPIOA_ModeCfg(GPIO_Pin_9, GPIO_ModeOut_PP_5mA); // TXD-配置推挽输出,注意要先让IO口输出高电平   x = 10 * GetSysClock() / 8 / 115200; //串口1定为115200波特率
  x = (x + 5) / 10; //整型运算中四舍五入
  R16_UART1_DL = (uint16_t)x; //给波特率寄存器赋值   R8_UART1_FCR = (2 << 6) | RB_FCR_TX_FIFO_CLR | RB_FCR_RX_FIFO_CLR | RB_FCR_FIFO_EN;
      //FIFO控制寄存器配置,10左移6位:触发点4字节;收发FIFO数据都清空;FIFO使能
  R8_UART1_LCR = RB_LCR_WORD_SZ; //线路控制寄存器配置,选择串口数据长度
  R8_UART1_IER = RB_IER_TXD_EN | RB_IER_RECV_RDY | RB_IER_LINE_STAT; //中断使能控制器配置,TX引脚输出使能;接收中断使能;接收线路状态中断使能
  R8_UART1_MCR |= RB_MCR_INT_OE; //调制解调器控制寄存器配置,允许串口的中断请求输出
  R8_UART1_DIV = 1; //用于波特率配置,参考手册中的公式   PFIC_EnableIRQ(UART1_IRQn); //中断注册   UART1_SendByte('O');
  UART1_SendByte('K');
} void u2u3_init(uint32_t btl) //波特率数字较大时需要用32位的整型存放,比如115200
{
  uint32_t x;   /* 配置串口2、3的IO口模式 */
  GPIOA_SetBits(GPIO_Pin_7);
  GPIOA_ModeCfg(GPIO_Pin_6, GPIO_ModeIN_PU);
  GPIOA_ModeCfg(GPIO_Pin_7, GPIO_ModeOut_PP_5mA);
  GPIOA_SetBits(GPIO_Pin_5);
  GPIOA_ModeCfg(GPIO_Pin_4, GPIO_ModeIN_PU);
  GPIOA_ModeCfg(GPIO_Pin_5, GPIO_ModeOut_PP_5mA);   x = 10 * GetSysClock() / 8 / btl;
  x = (x + 5) / 10;
  R16_UART2_DL = (uint16_t)x;
  R16_UART3_DL = (uint16_t)x; //寄存器为16位的   R8_UART2_FCR = (2 << 6) | RB_FCR_TX_FIFO_CLR | RB_FCR_RX_FIFO_CLR | RB_FCR_FIFO_EN;
  R8_UART2_LCR = RB_LCR_WORD_SZ;
  R8_UART2_IER = RB_IER_TXD_EN | RB_IER_RECV_RDY | RB_IER_LINE_STAT;
  R8_UART2_MCR |= RB_MCR_INT_OE;
  R8_UART2_DIV = 1;   R8_UART3_FCR = (2 << 6) | RB_FCR_TX_FIFO_CLR | RB_FCR_RX_FIFO_CLR | RB_FCR_FIFO_EN;
  R8_UART3_LCR = RB_LCR_WORD_SZ;
  R8_UART3_IER = RB_IER_TXD_EN | RB_IER_RECV_RDY | RB_IER_LINE_STAT;
  R8_UART3_MCR |= RB_MCR_INT_OE;
  R8_UART3_DIV = 1;   PFIC_EnableIRQ(UART2_IRQn);
  PFIC_EnableIRQ(UART3_IRQn);   baud_get = 1; //波特率已由串口1获得的标识   UART2_SendByte('O');
  UART2_SendByte('K');
  UART3_SendByte('O');
  UART3_SendByte('K');
} void main()
{
  uint8_t i,j;   SetSysClock(CLK_SOURCE_PLL_60MHz);
  u1_init(); //串口1默认115200波特率   while(!RxBuff1_get)
    __nop(); //等待串口1接收指令。串口1接收到一串数据之后,开始处理数据
  while(RxBuff1_get)
  {
    for(i=0; i<u1_i; i++)
    {
      j = R8_UART1_TFC; //查询 发FIFO计数寄存器的数值,数据过多时不发送数据给FIFO
      while(j > 4)
      {
        j = R8_UART1_TFC; //再读取一遍,等待FIFO有空间存放即将发送的数据。发送数据过快将导致与波特率不匹配而乱码
      }
    UART1_SendByte(RxBuff1[i]); //反馈上位机
    u1_get[i] = RxBuff1[i]; //将RxBuff1中的指令搬到u1_get中,方便仿真观察
    }
    RxBuff1_get = 0;
  }   baud_num = u1_get[5]-'0'; //将"baud:"之后的字符转换为数字
  for (i=6; i<u1_i; i++)
  {
  baud_num = baud_num *10;
  baud_num += u1_get[i]-'0';
  }   u2u3_init(baud_num); //初始化u2u3   while(baud_get) //获得波特率,并且u2u3初始化完成之后
  {
    __nop();
    while(u3_get_flag)
    {
      for(i=0; i<u3_i; i++)
      {
        j = R8_UART2_TFC; //查询 发FIFO计数寄存器的数值,还有数据时不发送
        while(j) //作用和上面判断FIFO数据是否过多类似,_TFC寄存器中的值最多为8,不让FIFO溢出即可
        j = R8_UART2_TFC;
        UART2_SendByte(RxBuff3[i]); //串口3收到的数据从串口2发出
      }
      if(i == u3_i)
      {
        u3_i = 0; //RxBuff3的数组指针归零
        u3_get_flag = 0; //清空串口3接收到数据的标志
      }
    }
  }
} __INTERRUPT //硬件压栈
__HIGH_CODE //放在ram里跑,更快
void UART1_IRQHandler(void)
{
  volatile uint8_t i;   switch(R8_UART1_IIR & RB_IIR_INT_MASK) //获取中断标志
  {
    case UART_II_LINE_STAT: // 线路状态错误
    {
      UART1_GetLinSTA(); //读取线路状态寄存器,读取该寄存器将自动清除中断
      break;
    }     case UART_II_RECV_RDY: // 数据达到设置触发点
      for(i = 0; i != trigB-1; i++)
      {  
        RxBuff1[u1_i] = UART1_RecvByte();
      u1_i++;
      }
      break;     case UART_II_RECV_TOUT: // 接收超时,暂时一帧数据接收完成。注意FIFO里要留有至少一个字符用来比较,判断超时
      i = UART1_RecvString(RxBuff1+u1_i);
      u1_i += i;
      RxBuff1_get = 1;
      break;     case UART_II_THR_EMPTY: // 发送缓存区空,可继续发送
      break;     default:
      break;
  }
} __INTERRUPT //硬件压栈
__HIGH_CODE //下方程序放在ram里跑,更快
void UART2_IRQHandler(void)
{
  volatile uint8_t i;   switch(R8_UART2_IIR & RB_IIR_INT_MASK) //获取中断标志
  {
    case UART_II_LINE_STAT: // 线路状态错误
    {
      UART2_GetLinSTA(); //读取线路状态寄存器,读取该寄存器将自动清除中断
      break;
    }     case UART_II_RECV_RDY: // 数据达到设置触发点
      for(i = 0; i != trigB; i++)
      {
        RxBuff2[i] = UART2_RecvByte();
        UART3_SendByte(RxBuff2[i]); //从串口3转发出去
      }
      break;     case UART_II_RECV_TOUT: // 接收超时,暂时一帧数据接收完成
      i = UART2_RecvString(RxBuff2);
      UART3_SendString(RxBuff2, i);
      break;     case UART_II_THR_EMPTY: // 发送缓存区空,可继续发送
      break;     default:
      break;
  }
} __INTERRUPT //硬件压栈
__HIGH_CODE //放在ram里跑,更快
void UART3_IRQHandler(void)
{
  volatile uint8_t i;
  switch(R8_UART3_IIR & RB_IIR_INT_MASK) //获取中断标志
  {
    case UART_II_LINE_STAT: //线路状态错误
    {
    UART3_GetLinSTA(); //读取线路状态寄存器,读取该寄存器将自动清除中断
    break;
    }     case UART_II_RECV_RDY: // 数据达到设置触发点
    for(i = 0; i != trigB-1; i++) //FIFO中留一个字节的数据,用于触发_TOUT标识
    {
      RxBuff3[u3_i++] = UART3_RecvByte();
      //UART2_SendByte(RxBuff3[i]); //先不从串口2转发,防止串口2的发送中断打断串口3的中断服务函数
    }
    break;     case UART_II_RECV_TOUT: // 接收超时,暂时一帧数据接收完成
      i = UART3_RecvString(RxBuff3+u3_i);
      u3_i += i;
      //UART2_SendString(RxBuff3, i); //先不从串口2转发,防止串口2的发送中断打断串口3的中断服务函数
      u3_get_flag = 1;
      break;     case UART_II_THR_EMPTY: // 发送缓存区空,可继续发送
      break;     default:
      break;
  }
}

CH582m串口透传程序的更多相关文章

  1. CC1101 433无线模块,STM8串口透传

    CC1101 433无线模块,STM8串口透传   原理图:http://download.csdn.net/detail/cp1300/7496509 下面是STM8程序 CC1101.C /*** ...

  2. tcp与串口透传(select)

    介绍 tcp作为服务端,监听端口8888,实现串口透传,这里是使用select监听tcp的receive和串口的read,单工通信 -p 指定tcp端口 -s 指定串口 -b 指定波特率 支持4800 ...

  3. ESP8266局域网 路由器下作服务器模式串口透传 arduino uno示例 模板参考2

    ESP8266服务器模式串口透传编译需要下载8266的库文件后才可以正常 准备工作 下载一个Arduino IDE,下载8266的库文件ESP8266服务器模式串口透传编译 功能说明 1.直接使用路由 ...

  4. ESP8266局域网智能家居 路由器下作服务器模式串口透传 无线通信控制 arduino uno示例 模板参考

    准备工作 下载一个Arduino IDE, 下载8266的库文件 ESP8266服务器模式串口透传编译 功能说明 1.直接使用路由器中转数据 2.手机放热点模式直接传输数据 两者有访问IP地址的差别, ...

  5. 18-ESP8266 SDK开发基础入门篇--TCP 服务器 RTOS版,串口透传,TCP客户端控制LED

    https://www.cnblogs.com/yangfengwu/p/11112015.html 先规定一下协议 aa 55 02 01 F1 4C 控制LED点亮  F1 4C为CRC高位和低位 ...

  6. 16-ESP8266 SDK开发基础入门篇--TCP 服务器 非RTOS运行版,串口透传(串口回调函数处理版)

    https://www.cnblogs.com/yangfengwu/p/11105466.html 其实官方给的RTOS的版本就是在原先非RTOS版本上增加的 https://www.cnblogs ...

  7. wifi实现串口透传

    环境: 串口服务器Ip:172.16.1.11 串口客户机ip:172.16.1.12 一.网络连接示意图 二.串口服务器的配置 参考:ser2net的编译及测试 三.串口客户端的配置 实际上这是一个 ...

  8. python 串口 透传

    python正常情况通过串口 serial  传输数据的时候,都是以字符串的形式发送的 str = ‘abcd’ ser.write(str.encode())#直接发送str报错,需要发送byte类 ...

  9. 蓝牙4.0BLE 手机控制 cc2540 CC2541 的串口透传功能已实现

           蓝牙4.0BLE 手机控制 cc2540 CC2541 的串口透传功能已实现        尽管蓝牙4.0 BLE芯片CC2540 是单芯片(即用户能够对它进行芯片级代码编写), 是80 ...

  10. ESP8266串口和MQTT服务器消息互传(版本一) 单纯透传+保存WIFI账号信息

    目标 制作一个ESP8266串口和MQTT相互透传的小WIFI,可用手机修改其连接的路由器,由此该模块可以任意加载到各种串口传输的单片机上,完成硬件到云端的传输. 1 实物图 2 MQTT网页测试客户 ...

随机推荐

  1. FFmpeg 解码内存泄漏汇总,sws_getContext函数无法释放问题

    使用FFmpeg库做的项目,调试项目的时候发现,连续解视频进行播放,会有明显内存增加问题.连续工作10个小时后就会 被linux 内核kill掉. 通过逐步注掉代码和网上查阅资料.最后发现内存泄漏有一 ...

  2. 推荐一款在浏览器编辑`Blazor`的`IDE`

    不知道是否有Blazor用户羡慕过React或者Vue用户,在一些组件库中,它们就提供了在当前的组件预览对于组件的实时编辑并且预览? 比如semi-design的这种 在比如codepen这种 由于B ...

  3. py教学之元组

    元组介绍 Python 的元组与列表类似,不同之处在于元组的元素不能修改. 元组使用小括号 ( ),列表使用方括号 [ ]. 元组创建很简单,只需要在括号中添加元素,并使用逗号隔开即可. tup1 = ...

  4. 论文翻译:2022_Phase-Aware Deep Speech Enhancement: It’s All About The Frame Length

    摘要 虽然相位感知语音处理近年来受到越来越多的关注,但大多数帧长约为32 ms的窄带STFT方法显示出相位对整体性能的影响相当温和.与此同时,现代基于深度神经网络(DNN)的方法,如Conv-TasN ...

  5. 对线面试官:浅聊一下 Java 虚拟机栈?

    对于 JVM(Java 虚拟机)来说,它有两个非常重要的区域,一个是栈(Java 虚拟机栈),另一个是堆.堆是 JVM 的存储单位,所有的对象和数组都是存储在此区域的:而栈是 JVM 的运行单位,它主 ...

  6. 面向对象程序设计(二):C++模板初探

    背景:老师留了一个作业,对两个数组进行相加,但是总是会出现错误:首先我们需要知道当数组作为参数传递的时候是不能用 sizeof 的,因为当数组传入子函数就变成了普通的数组头:这时候使用 sizeof ...

  7. Spring Boot整合JSP --CRUD

    Springboot整合JSP spring boot与视图层次的整合: JSP 效率低 Thymeleaf java Server page 是Java提供的一种动态的网页技术,低层是Servlet ...

  8. UI自动化中上传与唤醒弹窗

    本篇想谈的是在ui自动化中对上传的一些理解,干货满满. 一.是否有必要唤醒弹窗 以selenium为代表的库在进行文件上传时,是可以直接对输入框 "发送" 文件的,其send_ke ...

  9. windows server backup 无法使用或wbadmin.msc致命错误解决方法

    因为黑群辉断电无法自动引导进系统,我也找不到很好的办法,所以决定使用windows server来做NAS服务器,虽然都解决了内网穿透的问题,但是数据安全还在找方案,目前已经解决: 1.购买了一张pc ...

  10. Where do I Turn?(叉积)

    题目: Trouble came from the overseas lands: a three-headed dragon Gorynych arrived. The dragon settled ...