原创 改进的软件串口接收子程序

2024-6-23 08:59 265 1 1 分类: 软件与OS 文集: AVR
代码;
stduart.c

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

  项目:改进的延时法实现半双工软件串口
  文件:sfuart.c
  说明:软件串口驱动
        
  作者:邵子扬
  时间:2012年12月15日

*/
#include "sfduart.h"

// 循环延时调整系数
#define SFD_LOOP_VAR  12

// 软件串口初始化
void sfdUART_init(void)
{
  PINDIR(sfdUART_TXDIO, PIN_OUTPUT);
  PINSET(sfdUART_TXDIO);

  PINDIR(sfdUART_RXDIO, PIN_INPUT);
  PINSET(sfdUART_RXDIO);

  // 允许外中断1,下降沿触发方式
  MCUCR = (1 << ISC11);
  sfd_ENABLE_RXINT();
}

// 读取一个字节
char sfdUART_getbyte(void)
{
  unsigned char i, tmp;

  // 接收完成前,禁止接收中断,防止重复触发
  sfd_DISABLE_RXINT();

  // 起始位
  while(PININ(sfdUART_RXDIO));

  // 延时 1.4 比特位
  _delay_us(1400000UL / sfdBAUDRATE);

  // 读取8位数据
  for(i = tmp = 0; i < 8; i++)
  {
    tmp = tmp >> 1;
	if(PININ(sfdUART_RXDIO))
	  tmp |= 0x80;

    // 循环中,延时函数需要调整时间,去掉循环语句本身占用时间
    _delay_us(1000000UL / sfdBAUDRATE -  SFD_LOOP_VAR);
  }

  // 1个停止位
  _delay_us(1000000UL / sfdBAUDRATE);

  // 允许中断,接收下一个数据
  sfd_ENABLE_RXINT();

  return tmp;
}

// 发送一个字节
void sfdUART_sendbyte(char dat)
{
  unsigned char i;

  // 半双工串口,发送前禁止接收中断
  sfd_DISABLE_RXINT();

  // 起始位
  PINCLR(sfdUART_TXDIO);
  _delay_us(1000000UL / sfdBAUDRATE);

  for(i = 0; i < 8; i++)
  {
    if(dat & 0x01)
      PINSET(sfdUART_TXDIO);
    else
      PINCLR(sfdUART_TXDIO);

    dat = dat /2;

    // 延时时间需要根据循环中指令数量进行调整
    // 去掉指令占用时间,这个时间与指令数和时钟频率有关
    _delay_us(1000000UL / sfdBAUDRATE - SFD_LOOP_VAR);
  }

  // 停止位
  PINSET(sfdUART_TXDIO);
  _delay_us(1000000UL / sfdBAUDRATE);

  // 允许接收中断
  sfd_ENABLE_RXINT();

}

volatile char RXCflag = 0;

// 外部中断,检测接收数据的起始位
ISR(INT1_vect)
{
  // 检测到下降沿,设置接收标志位
  RXCflag = 1;

  // 禁止INT1中断,直到接收完成,避免重复触发
  sfd_DISABLE_RXINT();
}

main.c


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

  项目:改进的延时法实现半双工软件串口
  文件:main.c
  说明:软件串口的使用方法
        
  作者:邵子扬
  时间:2012年12月15日

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

#include 
#include 

// 波特率计算
#define UBRRREG (F_CPU / ( 8 * sfdBAUDRATE ) - 1)

// 初始化
void init()
{
  // 初始化软件串口
  sfdUART_init();
  sfdUART_sendbyte('>');

  // 初始化硬件串口
  // 使用硬件串口进行对比
  UBRRH = UBRRREG / 256;
  UBRRL = UBRRREG % 256;
  UCSRA = ( 1 << U2X );
  UCSRB = ( 1 << TXEN );
  UCSRC = ( 1 << UCSZ1) | ( 1 << UCSZ0 );

  sei();

}

int main(void)
{
  char tmp;

  init();        // 初始化

  for(;;)
  {
    if(RXCflag)  // 检测是否数据被接收
    {
      RXCflag = 0; // 清除检测标志
      tmp = sfdUART_getbyte(); // 接收数据
      UDR = tmp;               // 通过硬件串口返回数据作为对比
      sfdUART_sendbyte(tmp);   // 通过软件串口发送
    }

  }

  return 0;
}


仿真效果图:

PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
我要评论
0
1
关闭 站长推荐上一条 /3 下一条