目录

参考了沁恒官网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. Springboot+Dplayer+RabbitMQ实现视频弹幕延时入库

    编写之初,在网上找了很多关于springboot整合dplayer实现弹幕的方式,发现案例很少,然后自己就着手写一个小项目,分享给大家~ 注:Dplayer版本:v1.22.2 流程:前端自定义弹幕发 ...

  2. Vue导出模板、使用前端js办法导出表格数据、导入表格前端读取表格数据、导入表格发送后端读取数据

    以下是几种用的较多的函数方法,可以参考使用. // 導出1 myExport() { // post請求文件寫法1 const url = 'http://XXXX/XXXX/XXXX/XXXX' c ...

  3. 如何又快又好实现 Catalog 系统搜索能力?火山引擎 DataLeap 这样做

      摘要 DataLeap 是火山引擎数智平台 VeDI 旗下的大数据研发治理套件产品,帮助用户快速完成数据集成.开发.运维.治理.资产.安全等全套数据中台建设,降低工作成本和数据维护成本.挖掘数据价 ...

  4. 基于.NetCore开发博客项目 StarBlog - (26) 集成Swagger接口文档

    前言 这是StarBlog系列在2023年的第一篇更新~ 在之前的文章里,我们已经完成了部分接口的开发,接下来需要使用 curl.Postman 这类工具对这些接口进行测试,但接口一多,每次测试都要一 ...

  5. 【学习日志】MongoDB为什么选择B树,而MySQL选择B+树实现索引

    先说B树和B+树的区别 B树:非叶子节点也存储数据 B+树:只有叶子节点存储数据,且所有叶子节点通过指针相连接. 为什么MongoDB选择B树而,MySQL选择B+树呢?两种数据结构的区别摆在上面了, ...

  6. JavaScript 函数所能传递的最大参数

    取决于实现,取决于浏览器和操作系统标准没有规定(65535一般是有的) 来源:https://stackoverflow.com/questions/22747068/is-there-a-max-n ...

  7. JavaScript 、三个点、 ...、点点点 是什么语法

    笔者在学习ts函数式的时候见到这样的写法,这个语法是es6的扩展运算符,可以在函数调用/数组构造时, 将数组表达式或者string在语法层面展开:还可以在构造字面量对象时, 将对象表达式按key-va ...

  8. wsl 更新到D盘

    更换教程 https://blog.csdn.net/qq_39683682/article/details/113801632 安装后需要换个默认用户 https://blog.csdn.net/q ...

  9. 周末折腾了两天,踩了无数个坑,终于把win7装成了centos7

    上周五的时候,突发奇想,想把自己的Thinkpad E430C的操作系统装成linux. 熟悉电脑的都知道Thinkpad E430C很古老了,现在算来从2012年买来,到现在已经经历了10个年头了. ...

  10. Servlet HTTP Request Response笔记

    # 今日内容:    1. Servlet    2. HTTP协议    3. Request## Servlet:    1. 概念    2. 步骤    3. 执行原理    4. 生命周期  ...