使用普通定时器产生半双工软件串口

news2024/11/26 4:44:12

代码:

/*
  《AVR专题精选》随书例程
  
  3.通信接口使用技巧

  项目:使用普通定时器和外中断实现半双工软件串口
  文件:softuart.c
  说明:软件串口驱动文件
        
  作者:邵子扬
  时间:2012年12月16日

*/
#include "softuart.h"

// 声明软件串口变量
volatile struct TSOFTUART stUART;

// 初始化软件串口
void sfUART_init(void)
{
  // 设置IO状态
  PINDIR(sfUART_TXDIO, PIN_OUTPUT);
  PINSET(sfUART_TXDIO);
  PINDIR(sfUART_RXDIO, PIN_INPUT);
  PINSET(sfUART_RXDIO);
  
  // 初始化内部变量
  stUART.TXDcnt = 0;
  stUART.RXDcnt = 0;
  stUART.sfTXC  = 0;
  stUART.sfRXC  = 0;
  stUART.sfMODE = 0;

  // 设置定时器参数
  // CTC Mode
  // 分频系数=1
  OCR2 = F_CPU / sfBAUDRATE - 1;
  TCCR2 = (1 << WGM21);
  sf_START_TMR();  // 启动定时器

  // 设置外中断
  // 允许外中断1,下降沿触发方式
  MCUCR = (1 << ISC11);
  sfUART_mode(sfUART_mode_RXD);

}

// 设置软件串口工作模式
void sfUART_mode(char mode)
{
  char itmp;

  itmp = __save_interrupt();   // 保存中断状态
  cli();                       // 关中断

  stUART.sfMODE = mode;        // 设置工作模式
  if(stUART.sfMODE == sfUART_mode_TXD)
  {
    sf_START_TMR();
    sf_DISABLE_RXINT();
  }
  else
  {
    sf_STOP_TMR();
    sf_ENABLE_RXINT();
  }
  __restore_interrupt(itmp);   // 恢复中断
}

// 检查数据接收标志
char sfUART_RXC(void)
{
  return stUART.sfRXC;
}

// 检查数据发送完成标志
char sfUART_TXC(void)
{
  return stUART.sfTXC;
}

// 清除数据发送完成标志
void sfUART_clrTXC(void)
{
  stUART.sfTXC = 0;
}

// 读取数据
char sfUART_getbyte(void)
{
  stUART.sfRXC = 0;     // 清除数据接收标志
  return stUART.RXDBUF;
}

// 发送数据
// 调用函数后,数据只是放入发送缓冲区
// 发送过程由软件串口服务程序完成
void sfUART_sendbyte(char dat)
{
  stUART.TXDBUF = dat;  // 数据放入缓冲区
  stUART.sfTXC = 0;     // 清除标志位
  stUART.TXDcnt = 1;    // 开始发送
}

// 软件串口服务程序
void sfUART_svr(void)
{
  // 数据发送
  if(stUART.sfMODE == sfUART_mode_TXD)
  {
    // send
    switch(stUART.TXDcnt)
    {
      case 0:// 无数据
        break;
      case 1:// 起始位
        stUART.TXDcnt++;
        PINCLR(sfUART_TXDIO); // 设置IO输出低电平
        break;
      case 2:// 8位数据, 先发送低位
      case 3:
      case 4:
      case 5:
      case 6:
      case 7:
      case 8:
      case 9:
        if(stUART.TXDBUF & 0x01)
          PINSET(sfUART_TXDIO);
        else
          PINCLR(sfUART_TXDIO);
        stUART.TXDBUF = stUART.TXDBUF >> 1;
        stUART.TXDcnt++;
        break;
      case 10:// 停止位
        stUART.TXDcnt = 0;
        PINSET(sfUART_TXDIO);
        stUART.sfTXC = 1;
      default:
        break;
    }
  }
  else
  {
    // 接收
    switch(stUART.RXDcnt)
    {
      case 0:// 起始位
        stUART.RXDcnt = 1;
        stUART.RXDBUFtmp = 0;
        break;
      case 1:// 采样数据
      case 2:
      case 3:
      case 4:
      case 5:
      case 6:
      case 7:
      case 8:
        stUART.RXDBUFtmp = stUART.RXDBUFtmp >> 1;
        if(PININ(sfUART_RXDIO))
          stUART.RXDBUFtmp |= 0x80;
        stUART.RXDcnt++;
        break;
      case 9:// 停止位
        stUART.sfRXC = 1;
        stUART.RXDcnt = 0;
        sf_STOP_TMR();      // 停止定时器
        stUART.RXDBUF = stUART.RXDBUFtmp;
        sf_ENABLE_RXINT();  // 允许外部中断, 可以接收后面的数据
        break;
      default:
        break;
    }
  }
}

// 定时器中断服务程序
ISR(TIMER2_COMP_vect, ISR_NOBLOCK)
{
  sfUART_svr();  // 需要调用软件串口服务程序

}

// 外部中断服务程序
ISR(INT1_vect, ISR_NOBLOCK)
{
  // 禁止INT1中断,直到接收完成,避免重复触发
  sf_DISABLE_RXINT();

  stUART.RXDcnt = 1;
  TCNT2 = OCR2 / 16;
  sf_START_TMR();  // 启动定时器, 接收数据
}

main.c

/*
  《AVR专题精选》随书例程
  
  3.通信接口使用技巧

  项目:使用普通定时器和外中断实现半双工软件串口
  文件:main.c
  说明:主程序,演示软件串口的使用方法
        
  作者:邵子扬
  时间:2012年12月16日

*/
#include "cfg.h"
#include "macromcu.h"
#include "softuart.h"

#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>


int main()
{
  unsigned int UBRRREG;
  unsigned char tmp;

  sfUART_init();  // 软件串口初始化

  // 设置硬件串口作为对比
  UBRRREG = F_CPU / ( 8 * sfBAUDRATE ) - 1;
  UBRRH = UBRRREG / 256;
  UBRRL = UBRRREG % 256;
  UCSRA = ( 1 << U2X );
  UCSRB = ( 1 << TXEN );
  UCSRC = ( 1 << UCSZ1 ) | ( 1 << UCSZ0 );

  sei();  // 开中断

  sfUART_mode(sfUART_mode_TXD);  // 设置为发送模式
  sfUART_sendbyte('>');          // 发送提示字符
  _delay_ms(100);                // 延时100ms,等待发送完成
  sfUART_mode(sfUART_mode_RXD);  // 切换为接收模式

  for(;;)
  {
    if(sfUART_RXC())             // 是否接收到数据
    {
      tmp = sfUART_getbyte();    // 读取数据
      UDR = tmp;                 // 发送到硬件串口
      sfUART_mode(sfUART_mode_TXD); // 切换到发送模式
      sfUART_sendbyte(tmp);      // 通过软件串口发送
    }
    if(sfUART_TXC())             // 发送完成
    {
      sfUART_clrTXC();           // 清除发送完成标志
      sfUART_mode(sfUART_mode_RXD); // 切换回接收模式
    }

  }

  return 0;
}

仿真效果图:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1852313.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

YOLOv9基础 | 实时目标检测新SOTA,手把手带你深度解析yolov9论文!

前言:Hello大家好,我是小哥谈。YOLOv9是Chien-Yao Wang等人提出的YOLO系列的最新版本之一(截止到目前,YOLOv10已发布),于2024年2月21日发布。它是 YOLOv7的改进版本,两者均由Chien-Yao Wang及其同事开发。本节课就以YOLOv9论文为基础带大家深入解析YOLOv9算法。🌈 …

web基础学习

1、安装 1.1、创建一个 React 新项目 如果你正在学习 React 或者考虑将其应用到现有的项目中&#xff0c;你可以 利用 script 标签将 React 添加到任何 HTML 页面 来快速开启学习之旅。如果你的项目需要许多组件和许多文件&#xff0c;那就需要考虑以下方式了&#xff01; 1…

WinMerge v2 (开源的文件比较/合并工具)

前言 WinMerge 是一款运行于Windows系统下的免费开源的文件比较/合并工具&#xff0c;使用它可以非常方便地比较多个文档内容甚至是文件夹与文件夹之间的文件差异。适合程序员或者经常需要撰写文稿的朋友使用。 一、下载地址 下载链接&#xff1a;http://dygod/source 点击搜…

【干货】Android中高级开发进阶必备资料(附:PDF+视频+源码笔记)

4、数据传输与序列化 5、Java虚拟机原理 6、高效IO 设计思想解读开源框架 随着互联网企业的不断发展&#xff0c;产品项目中的模块越来越多&#xff0c;用户体验要求也越来越高&#xff0c;想实现小步快跑、快速迭代的目的越来越难&#xff0c;插件化技术应用而生。如果没有…

Python: HexBinDecOct

因为&#xff1a; f0b1001110# 十进制 int()a0*2**01*2**11*2**21*2**30*2**40*2**51*2**6print(a)# 八进制 oct()print(78/8,78%8)# 110 001 001 8 116print(1*2**00*2**10*2**2,1*2**00*2**10*2**2,0*2**01*2**11*2**2)#十六进制 hex()#0 100 1110 16 4Eprint(sixteenFoo(0*…

leetcode 二分查找·系统掌握 第一个错误版本

题意&#xff1a; 题解&#xff1a; 就是经典的~01~泛型查找&#xff0c;而且一定存在这样错误的版本所以查找不会"失败"&#xff0c;返回每次查找结果即可。 int firstBadVersion(int n) {long l1,rn,mid;while(l<r){mid(lr)>>1;if(isBadVersion(mid))r…

wordpress教程自动采集并发布工具

随着互联网的快速发展&#xff0c;越来越多的人开始关注网络赚钱。而对于许多人来说&#xff0c;拥有一个自己的个人网站是一个不错的选择。然而&#xff0c;要让自己的个人网站内容丰富多样&#xff0c;就需要不断地进行更新。那么&#xff0c;有没有一种方法可以让我们轻松地…

【大数据 复习】第7章 MapReduce(重中之重)

一、概念 1.MapReduce 设计就是“计算向数据靠拢”&#xff0c;而不是“数据向计算靠拢”&#xff0c;因为移动&#xff0c;数据需要大量的网络传输开销。 2.Hadoop MapReduce是分布式并行编程模型MapReduce的开源实现。 3.特点 &#xff08;1&#xff09;非共享式&#xff0c;…

Java学习 - 网络IP协议簇 讲解

IP协议 IP协议全称 Internet Protocol互联网互连协议 IP协议作用 实现数据在网络节点上互相传输 IP协议特点 不面向连接不保证可靠 IP协议数据报结构 组成说明版本目前有IPv4和IPv6两种版本首部长度单位4字节&#xff0c;所以首部长度最大为 15 * 4 60字节区分服务不同…

深度学习windows环境配置

1 下载CUDA和cudnn 详见文章 CUDA与CUDNN在Windows下的安装与配置&#xff08;超级详细版&#xff09;_windows cudnn安装-CSDN博客 我电脑的CUDA下载链接如下 ​​​​​https://developer.nvidia.com/cuda-12-1-0-download-archive?target_osWindows&target_archx86…

第10章 启动过程组 (制定项目章程)

第10章 启动过程组 9.1制定项目章程&#xff0c;在第三版教材第356~360页&#xff1b; 文字图片音频方式 视频12 第一个知识点&#xff1a;主要输出 1、项目章程&#xff08;重要知识点&#xff09; 项目目的 为了稳定与发展公司的客户群(抽象&#xff0c;非具体) 可测量的项目…

Pytho字符串的定义与操作

一、字符串的定义 Python 字符串是字符的序列&#xff0c;用于存储文本数据。字符串可以包括字母、数字、符号和空格。在 Python 中&#xff0c;字符串是不可变的&#xff0c;这意味着一旦创建了一个字符串&#xff0c;就不能更改其中的字符。但是&#xff0c;你可以创建新的字…

头歌资源库(15)活动安排问题

一、 问题描述 二、算法思想 这是一个经典的贪心算法问题&#xff0c;可以使用贪心算法进行求解。 首先&#xff0c;将所有活动按照结束时间从小到大进行排序。假设已经排好序的活动列表为S。 然后&#xff0c;选择第一个活动&#xff0c;将其加入到安排列表中。 接下来&…

mysql中返回日期格式带有T、Java解决返回日期格式带 ‘T‘ 问题、MySQL查询日期为什么带T、java.util.Date()类型为什么有T

文章目录 一、场景描述&#xff1a;Mysql返回日期格式带有T二、解决方法2.1、方法一&#xff1a;通过注解格式化2.2、方法二&#xff1a;通过全局配置2.3、方法三&#xff1a;查询时手动转换时间格式 三、mysql 数据库时间类型数据为什么有T3.1、什么是ISO 8601格式 四、java中…

字节跳动+京东+360+网易+腾讯,那些年我们一起踩过算法与数据结构的坑!(1)

**二面&#xff1a;**已知一棵树的由根至叶子结点按层次输入的结点序列及每个结点的度&#xff08;每层中自 左到右输入&#xff09;&#xff0c;试写出构造此树的孩子-兄弟链表的算法。 **三面主管面&#xff1a;**已知一棵二叉树的前序序列和中序序列分别存于两个一维数组中&…

Java基础的重点知识-03-方法与数组

文章目录 方法数组 方法 定义方法的格式详解 修饰符 返回值类型 方法名(参数列表){//代码省略...return 结果; }修饰符&#xff1a; public static 固定写法返回值类型&#xff1a; 表示方法运行的结果的数据类型&#xff0c;方法执行后将结果返回到调用者参数列表&#xff1…

[实践篇]13.29 再来聊下Pass Through设备透传

写在前面 为什么要再聊天Pass Through? 因为在QNX + Linux Android的技术方案下,我们会遇到LA发生reboot或异常panic后,无法正常开机。而再次异常的原因确实最头疼的Memory Corruption。观察下来是由于一些DMA外设如使用UART的一些设备在重启或panic后,没有正常走Shutdow…

基于matlab的BP神经网络分类预测

1.神经网络结构 本文网络结构如图1所示&#xff1a; 图1 网络结构 图1给出的并不是单纯的bp神经网络结构这里设置了三个隐藏层&#xff0c;神经元个数分别为6&#xff0c;3&#xff0c;3&#xff0c;输入层12个特征输入&#xff0c;输出层输出4个类型结果。 2.代码 %% 清空环…

机器学习好神奇,来看看Lasso的超参数调整与模型选择

目录 一、什么是机器学习&#xff1f;二、稀疏建模介绍三、Lasso回归简介四、Lasso超参数调整与模型选择 一、什么是机器学习&#xff1f; 机器学习是一种人工智能技术&#xff0c;它使计算机系统能够从数据中学习并做出预测或决策&#xff0c;而无需明确编程。它涉及到使用算…

RocketMQ源码学习笔记:Broker启动流程

这是本人学习的总结&#xff0c;主要学习资料如下 马士兵教育rocketMq官方文档 目录 1、Broker启动流程2、一些重要的类2.1、MappedFile2.2、MessgeStore2.3、MessageStore的加载启动流程 3、技术亮点3.1、 内存映射3.1.1、简介3.1.2、源码 1、Broker启动流程 Broker启动流程…