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

2024-06-23 10:20

本文主要是介绍使用普通定时器产生半双工软件串口,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

代码:

/*《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// 分频系数=1OCR2 = 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){// sendswitch(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);elsePINCLR(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.chinasem.cn/article/1086883

相关文章

Java使用Javassist动态生成HelloWorld类

《Java使用Javassist动态生成HelloWorld类》Javassist是一个非常强大的字节码操作和定义库,它允许开发者在运行时创建新的类或者修改现有的类,本文将简单介绍如何使用Javass... 目录1. Javassist简介2. 环境准备3. 动态生成HelloWorld类3.1 创建CtC

使用Python批量将.ncm格式的音频文件转换为.mp3格式的实战详解

《使用Python批量将.ncm格式的音频文件转换为.mp3格式的实战详解》本文详细介绍了如何使用Python通过ncmdump工具批量将.ncm音频转换为.mp3的步骤,包括安装、配置ffmpeg环... 目录1. 前言2. 安装 ncmdump3. 实现 .ncm 转 .mp34. 执行过程5. 执行结

Java使用jar命令配置服务器端口的完整指南

《Java使用jar命令配置服务器端口的完整指南》本文将详细介绍如何使用java-jar命令启动应用,并重点讲解如何配置服务器端口,同时提供一个实用的Web工具来简化这一过程,希望对大家有所帮助... 目录1. Java Jar文件简介1.1 什么是Jar文件1.2 创建可执行Jar文件2. 使用java

C#使用Spire.Doc for .NET实现HTML转Word的高效方案

《C#使用Spire.Docfor.NET实现HTML转Word的高效方案》在Web开发中,HTML内容的生成与处理是高频需求,然而,当用户需要将HTML页面或动态生成的HTML字符串转换为Wor... 目录引言一、html转Word的典型场景与挑战二、用 Spire.Doc 实现 HTML 转 Word1

Java中的抽象类与abstract 关键字使用详解

《Java中的抽象类与abstract关键字使用详解》:本文主要介绍Java中的抽象类与abstract关键字使用详解,本文通过实例代码给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧... 目录一、抽象类的概念二、使用 abstract2.1 修饰类 => 抽象类2.2 修饰方法 => 抽象方法,没有

MyBatis ParameterHandler的具体使用

《MyBatisParameterHandler的具体使用》本文主要介绍了MyBatisParameterHandler的具体使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参... 目录一、概述二、源码1 关键属性2.setParameters3.TypeHandler1.TypeHa

Spring 中的切面与事务结合使用完整示例

《Spring中的切面与事务结合使用完整示例》本文给大家介绍Spring中的切面与事务结合使用完整示例,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考... 目录 一、前置知识:Spring AOP 与 事务的关系 事务本质上就是一个“切面”二、核心组件三、完

使用docker搭建嵌入式Linux开发环境

《使用docker搭建嵌入式Linux开发环境》本文主要介绍了使用docker搭建嵌入式Linux开发环境,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面... 目录1、前言2、安装docker3、编写容器管理脚本4、创建容器1、前言在日常开发全志、rk等不同

使用Python实现Word文档的自动化对比方案

《使用Python实现Word文档的自动化对比方案》我们经常需要比较两个Word文档的版本差异,无论是合同修订、论文修改还是代码文档更新,人工比对不仅效率低下,还容易遗漏关键改动,下面通过一个实际案例... 目录引言一、使用python-docx库解析文档结构二、使用difflib进行差异比对三、高级对比方

sky-take-out项目中Redis的使用示例详解

《sky-take-out项目中Redis的使用示例详解》SpringCache是Spring的缓存抽象层,通过注解简化缓存管理,支持Redis等提供者,适用于方法结果缓存、更新和删除操作,但无法实现... 目录Spring Cache主要特性核心注解1.@Cacheable2.@CachePut3.@Ca