目录

参考了沁恒官网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. 聚合查询、分组查询、ORM中如何给表再次添加新的字段、F与Q查询、ORM查询优化、ORM事务操作、ORM常用字段类型、ORM常用字段参数、Ajax、数据编码格式(Content-Type)、ajax携带文件数据

    今日内容 聚合查询 在ORM中支持单独使用聚合函数,需要使用aggregate方法. 聚合函数:Max最大.Min最小.Sum总和.Avg平均.count统计 from django.db.model ...

  2. cordova完整版本创建、修改自定义插件重新调试步骤带截图

    创建第三方插件 npx plugman create --name myplugin --plugin_id xiao.jin.plugin --plugin_version 1.0.0 添加平台支持 ...

  3. AJAX容易出错地方,错误处理

    myajax.js   //创建路由器对象 const express=require('express'); //引入连接池模块 const pool=require('../pool.js'); ...

  4. Docker快速部署Nacos

    前置 机器配置不能太低 ( 2c2g的轻量服务器直接崩掉了) Docker https://www.docker.com/ 开始安装 mysql 使用docker安装mysql (推荐8.0) 可以不 ...

  5. 【Android 4.4】内存文件系统(tmpfs)的创建与使用

    前言说明 某些情况下,需要缓存一些文件到磁盘中,我们可以借助 tmpfs 文件系统,来提升读写缓存文件的速度,并且也可以避免频繁读写缓存文件所带来的对 flash 的寿命影响. 使用方法 通过 mkd ...

  6. JSP第七次作业

    1.做一个图书类Book id,name,price ,get,set访问器,构造方法2个,1个无参,1个有参做一个测试类,在main中创建3个图书对象,放到list集合中.做一个菜单,可以添加,删除 ...

  7. 基于 Ubuntu 服务器配置原生的 Socks5 网关代理服务器

    常见的代理协议有 http.https.socks4/5 这三种,http协议的代理搭建方案最简单,但是http代理无法访问https网站,https代理无法实现调用远端dns,所以我个人推荐使用Sc ...

  8. 一个关于DOM的小小思考

    在学习过程中碰见这样一个方法(原生JavaScript可使用的方法): document.querySelector('div').innerHTML=` <h2>编号:${resp.id ...

  9. vue-cli环境搭建 (超详细保姆级教程)

    一.使用之前,我们先来掌握3个东西是用来干什么的. npm: Nodejs下的包管理器. webpack: 它主要的用途是通过CommonJS的语法把所有浏览器端需要发布的静态资源做相应的准备,比如资 ...

  10. try-catch易错分析

    /* * @author YAM */public class Test01 { public static void main(String[] args) { try { showExce(); ...