文章
博客 网店

 AVR单片机普通I/O口模拟UART发送数据


有两种情况使得普通I/O口模拟UART发送数据变得很有实用意义
1.我们使用了一个类似ATTINY26这样的没有UART接口的单片机,在调试阶段我们需要查看单片机内部的一些数据(例如A/D转换结果)时。
2.在设计中我们为了数据通信(例如RS485,CAN等)已经使用了仅有的一个UART接口,再没有一个很好的与计算机连接的接口时。

用软件实现UART功能时完全可能的,但这要消耗一定的处理器资源,通常实现一个完整的UART那么需要有一个(或两个)定时器,一个外部中断,两个普通的I/O口用于RXD和TXD。
出于调试目的的软UART没有必要实现发送和接收全功能,如果仅仅时想从计算机屏幕上查看类似A/D转换结果这样的数据,那么主要实现发送功能即可。下面时我在ATTINY26上实现的UART发送模块,它在自动标定的内部1MHz时钟频率下工作,发送格式为波特率:9600,8个数据位,1个停止位。

接口函数声明头文件:

//sim_uart.h
#ifndef SIM_UART_H
#define SIM_UART_H

void suart_init(void);
void suart_write_byte(uint8_t dat);

#endif


源程序文件:


/******sim_uart.c 模拟UART发送程序**********
//内部校准的1MHz时钟下工作,发送波特率为9600
//本模块用PA6模拟UART的TXD引脚实现发送数据功能
//资源:一个CTC(比较匹配时清零)功能的定时器
//MCU:attiny26
//编译:WinAVR20070525
//芯艺设计室   http://www.chipart.cn
//2008-06-29
//本程序在实际硬件上调试通过!
********************************************/

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

#include"main.h"

//模拟发送I/O端口操作定义
#define DEBUG_PORT_INIT DDRA|=_BV(PA6)
#define DEBUG_PORT_SET  PORTA|=_BV(PA6)
#define DEBUG_PORT_CLR  PORTA&=~_BV(PA6)

static volatile uint8_t g_EndFlag;//发送完成标记
static uint8_t g_SendCounter;      //发送计数器
static uint8_t g_SendData;        //发送数据

//功能初始化
void suart_init(void)
{
  TCNT1=0;
  TCCR1A=0;
  
  //TC1计数到OCR1C的值时会自动清零并产生溢出中断
  //产生中断的频率应等于发送位时间,即波特率的倒数
  //TC1预分频为1,即不分频
  //(1/9600)/(1/1MHz)=1000 000/9600=一个位时间内的计数值=104
  OCR1C=104;            
  TIMSK=_BV(TOIE1);  //定时器溢出中断允许
  
  DEBUG_PORT_INIT;  //发送用I/O口初始化为输出
  DEBUG_PORT_SET;  //默认状态为高
}

//定时器溢出中断处理函数
ISR(TIMER1_OVF1_vect)
{
  switch(g_SendCounter)
  {
    case 0:        //开始位
      DEBUG_PORT_CLR;
      break;
    case 9:       //停止位
      DEBUG_PORT_SET;
      break;
    case 10:      //发送完成
      TCCR1B=0x80;//计数器停止
      g_EndFlag=1;//设置完成标记
      break;
    default:      //数据
      if(g_SendData&0x01)
        DEBUG_PORT_SET;
      else
        DEBUG_PORT_CLR;
      g_SendData>>=1;        
      break;
  }
  g_SendCounter++;
  LED_Y_FLASH;
}
//阻塞发送一个字节
void suart_write_byte(uint8_t dat)
{
  g_EndFlag=0;
  g_SendCounter=0;
  g_SendData=dat;

  TCNT1=0;      //等待一个位时间后从中断开始发送
  TCCR1B=0x81;  //计数器开始计数,并与OCR1C匹配时清零
  while(g_EndFlag==0);  //等待发送完成
  LED_Y_CLR;
}



芯艺工作室    蒙ICP备06005492号
Copyright© 2004-2023 ChipArt Studio All Rights Reserved