利用定时器1产生全双工软件串口

代码;

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

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

*/
#include "softuart.h"

// 内部变量
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;

  // 定时器初始化
  // CTC Mode
  // 分频比: 1
  OCR1A = 1;
  ICR1  = (F_CPU / sfBAUDRATE) - 1;
  TCCR1A = 0x00;
  TCCR1B = (1 << WGM13)|(1 << WGM12)|(1 << CS10);
  TIMSK = (1 << OCIE1A)|(0 << OCIE1B);

  // 外中断初始化
  // INT1
  // 允许外中断1,下降沿触发方式
  MCUCR = (1 << ISC11);
  sf_ENABLE_RXINT();

}

// 检查数据接收标志
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_TXDsvr(void)
{
  switch(stUART.TXDcnt)
  {
    case 0:// 无数据
      return;
    case 1:// 发送起始位
      stUART.TXDcnt++;
      PINCLR(sfUART_TXDIO);
      break;
    case 2:// 发送数据
    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;
      break;
    default:
      stUART.TXDcnt = 0;
      return;

  }
}

// 软件串口数据接收服务程序
void sfUART_RXDsvr(void)
{
  switch(stUART.RXDcnt)
  {
    case 0:// 接收起始位
      stUART.RXDBUF = 0;
      stUART.RXDcnt++;
      break;
    case 1:// 接收数据位
    case 2:
    case 3:
    case 4:
    case 5:
    case 6:
    case 7:
    case 8:
      stUART.RXDBUF = stUART.RXDBUF >> 1;
      if(PININ(sfUART_RXDIO))
        stUART.RXDBUF |= 0x80;
      stUART.RXDcnt++;
      break;
    case 9:// 停止位
      stUART.sfRXC = 1;
      sf_RXD_STOP();
      GIFR |= (1<<INTF1);
      sf_ENABLE_RXINT();
      break;
    default:
      return;
  }
}

main.c

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

  项目:使用AVR定时器1和外中断实现全双工软件串口
  文件: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>

#define UBRRREG  (F_CPU / ( 8 * sfBAUDRATE ) - 1)

// 定时器1 COMPA中断服务程序
ISR(TIMER1_COMPA_vect, ISR_NOBLOCK)
{
  sfUART_TXDsvr();  // 软件串口发送服务程序
}

// 定时器1 COMPB中断服务程序
ISR(TIMER1_COMPB_vect, ISR_NOBLOCK)
{
  sfUART_RXDsvr();  // 软件串口接收服务程序
}

// 外中断服务程序
ISR(INT1_vect)
{
  sf_DISABLE_RXINT();  // 禁止外中断, 避免重复触发
  sf_RXD_START();      // 启动接收程序
}

int main(void)
{
  unsigned char tmp;

  PORTB = 0xFF;        // 仿真时, PB2(SS)需要设置为高电平
                       // 否则会出错. 实际使用时不需要

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

  // 使用硬件串口作为对比
  UBRRH = UBRRREG / 256;
  UBRRL = UBRRREG % 256;
  UCSRA = ( 1 << U2X );
  UCSRB = ( 1 << TXEN );
  UCSRC = ( 1 << UCSZ1) | ( 1 << UCSZ0 );
  
  sei(); // 开中断


  for(;;)
  {

    if(sfUART_RXC())  // 接收到新数据
    {
      tmp = sfUART_getbyte(); // 读取数据
      UDR = tmp;              // 发送到硬件串口
      sfUART_sendbyte(tmp);   // 发送到软件串口
    }
    if(sfUART_TXC())  // 数据发送完成
    {
      sfUART_clrTXC();// 清除发送完成标志
    }

  }

  return 0;

}

仿真效果图:

相关推荐
重生之我是数学王子3 小时前
点亮核心板小灯 STM32U575
stm32·单片机·嵌入式硬件
end_SJ3 小时前
初学stm32 --- 定时器中断
stm32·单片机·嵌入式硬件
南城花随雪。3 小时前
单片机:实现数码管动态显示(0~99999999)74hc138驱动(附带源码)
单片机·嵌入式硬件
南城花随雪。5 小时前
单片机:实现信号发生器(附带源码)
单片机·嵌入式硬件
灵槐梦7 小时前
【速成51单片机】2.点亮LED
c语言·开发语言·经验分享·笔记·单片机·51单片机
三月七(爱看动漫的程序员)7 小时前
HiQA: A Hierarchical Contextual Augmentation RAG for Multi-Documents QA---附录
人工智能·单片机·嵌入式硬件·物联网·机器学习·语言模型·自然语言处理
新晨单片机设计8 小时前
【087】基于51单片机智能宠物喂食器【Proteus仿真+Keil程序+报告+原理图】
嵌入式硬件·51单片机·proteus·宠物·ad原理图
大风起兮129 小时前
STM32HAL库中RTC闹钟设置时分秒,年月日
stm32·嵌入式硬件
超能力MAX9 小时前
IIC驱动EEPROM
单片机·嵌入式硬件·fpga开发
QQ5471760529 小时前
stm32实现回调功能
stm32·单片机·嵌入式硬件