目录

参考了沁恒官网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. PHP转Go实践:xjson解析神器「开源工具集」

    前言 近期会更新一系列开源项目的文章,新的一年会和大家做更多的开源项目,也欢迎大家加入进来. xutil 今天分享的文章源自于开源项目jinzaigo/xutil的封装. 在封装过程中,劲仔将实现原理 ...

  2. 使用prometheus来避免Kubernetes CPU Limits造成的事故

    使用prometheus来避免Kubernetes CPU Limits造成的事故 译自:Using Prometheus to Avoid Disasters with Kubernetes CPU ...

  3. Azure Terraform(十二)利用 Terraform 将文件上传到 Azure Blob Storage

    一,引言 本篇文章中,我门将学习如何利用 Terraform 将 文件以及文件夹上传到 Azure Blob Storage,这个对于我们来说很方便,可以将一些不重要的内容也存储在源代码管理工具中! ...

  4. Java入门与进阶P-4.3+P-4.4

    循环控制 素数 只能被1和自己整除的数,不包括1 2 3 5 7 11 13 17 19 ... 1.循环控制语句 可以在满足循环条件的请款下,反复的执行某一段代码,这段被重复执行的代码被称为循环体语 ...

  5. ARM启动顺序

    iROM(也叫BL0)的作用:   初始化系统时钟,设置看门狗,初始化栈和堆   加载BL1 BL1的作用:   初始化RAM , 关闭Cache , 设置栈   加载BL2 BL2的作用:   初始 ...

  6. Java的两个好用的工具包 Apache commons

    Apache commons 介绍 这是apache commons lang3的工具类的截图 这个工具,小皮一般用在业务层较多 这是apache commons codec下面的工具 这个工具包,今 ...

  7. 【RocketMQ】DLedger选主源码分析

    RocketMQ 4.5版本之前,可以采用主从架构进行集群部署,但是如果master节点挂掉,不能自动在集群中选举出新的Master节点,需要人工介入,在4.5版本之后提供了DLedger模式,使用R ...

  8. Java 集合中的排序算法浅析

    作者:京东物流 秦彪 1.  引言 排序是一个Java开发者,在日常开发过程中随处可见的开发内容,Java中有丰富的API可以调用使用.在Java语言中,作为集合工具类的排序方法,必定要做到通用.高效 ...

  9. vue3 setup语法糖下,vue自定义指令的实现,以及指令全局挂载,自定义v-loading的实现

    最近一段时间,在做h5的移动端项目,UI组件库使用的vant,vant组件中的loading实在难用,无法包裹某个块进行loading,也无法对非组件的标签进行loading,所以想着自定义写个指令, ...

  10. MySQL数据类型补充

    数据类型 整数数据类型 特殊说明: ​ 对于整数类型,MySQL还支持在类型名称后面加小括号(M),而小括号中的M表示显示宽度,M的取值范围是(0, 255).int(M)这个M在字段的属性中指定了u ...