DIY编程器网

 找回密码
 注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 864|回复: 0
打印 上一主题 下一主题

AVR软件模拟串口程序

[复制链接]
跳转到指定楼层
楼主
发表于 2012-1-27 17:25:39 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
找个双串口单片机真是麻烦,所以想做个软件串口玩玩

环境:
winAVR
M48,8MHz
9600,1,8,1

输出:用定时器控制普通IO口输出位
输入:用外部中断+定时器,判断位的宽度

好几天没休息好了,利用闲暇写的,也没找到别人的参考程序,不过终于算是可以工作了,其实还应该有很多其它的方法可以试一下,比如用PWM输出串行数据,用输入捕获接收数据,或定时查询,或用任意一个IO口中断,则每个引脚都有可能

现在还有些问题,全双工同时收发时发送偶尔出错,别的中断干扰所致吧,占用两个定时器有些浪费,以后再修改吧,最好加上各种波率。软件串口终究不如原串口好用,不过要求不苛刻的话可以一用,如果波特率改到4800应该会稳定许多

本程序为直接摘出部分,删了无关的部分,在此可能有些变量没用,或有段落遗漏,请谅

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

#define Sbit1() PORTD|=1<<PD1
#define Sbit0() PORTD&=~(1<<PD1)


volatile unsigned int
eep_ms,//毫秒计时
keytime,          //等待时间
SoundOnTime;          ////
volatile unsigned char
rdata,
key,
start=0,
keycode,    //
*TxPoint,
rtime,
INT0_time,        //中断次数

RxLength=0,    //接收长度
RUDR,      //摸拟串口接收的数据
TxLength,          //串口发送数据长度
SUDR;            //串口发送的数据

unsigned char arr[10],DispBuff[10];


void Initial_IO(void)//IO口初始化
  {
   DDRD = 0X82;       //PD1串口输出,PD0串口输入,PD2模拟串口输入(INT0)
   PORTD = 0X82;       //PD1输出高电平
  }

void Initial_INT0(void)
  {
  EICRA|=(1<<ISC00);//边沿触发
   EIMSK|=1<<INT0;
  }

void Initial_timer0(void)             //定时器0初始化
  {
   TCCR0B|=(1<<CS01);              //定时器0:8M/8分频
   TIMSK0|=(1<<TOIE0);
  }

void Initial_timer1(void)
  {
   TCCR1A=(1<<WGM11);         
     TCCR1B=(1<<WGM13)|(1<<WGM12)|(1<<CS11); //定时器1 频率1MHz
   ICR1=1000;
   TIMSK1|=(1<<TOIE1);
  }

void Initial_timer2(void)
  {
   TCCR2B=(1<<CS22); //系统频率/64分频,8us
   TIMSK2|=(1<<TOIE2);                  //中断允许
  }


void Initial_WDR(void)                    //看门狗初始化
  {
  wdt_enable(WDTO_1S);
  wdt_reset();
  }


void Initial(void)
{
  Initial_IO();
  Initial_timer0();
  Initial_timer1();
  Initial_timer2();
  Initial_INT0();
  Initial_WDR();
  sei();
}


/*启动串口发送*/
void SendData(unsigned char *P,unsigned char DataLength)
  {
  TxLength=DataLength;
  TxPoint=P;
  start=0;
  }
  

int main (void)
  {

  Initial();

  while(1)
    {
    wdt_reset();
    if((rdata)&&(eep_ms>10))//收到数据延时10mS后启动发送,回送验证数据
      {
      key=0;
      SendData(&DispBuff[0],9);//发送DispBuff[0]的9位数据
      while(TxLength);//等待发送完成
      rdata=0;
      eep_ms=0;
      }
    }
  }


/*定时器0,100us溢出中断*/
SIGNAL(SIG_OVERFLOW0)
  {
  TCNT0=151;//重载数据,计时区间为151---255,共104uS,一个位的时间
  if(TxLength)//
    {
    if(start==0)
      {
      Sbit0();//起始位
      SUDR=*(TxPoint++);
      }
    else
      {
      if((start<=8))
        {
        if(SUDR&(1<<(start-1)))Sbit1();//数据1
        else Sbit0();//数据0
        }
      else Sbit1();//停止位
      }
    if(start<10)start++;
    else
      {
      TxLength--;//一字节 发送完成,字节数减1
      start=0;
      }//
    }
  }

/*定时器1,1ms溢出中断*/
SIGNAL(SIG_OVERFLOW1)
{
  eep_ms++;
}
/*定时器2*/
SIGNAL(SIG_OVERFLOW2)
  {
  sei();  
  if(INT0_time)//有数据
    {
    INT0_time=0;//中断次数清0
    rdata=1;//置有数据标志
    eep_ms=0;
    if(RxLength<10)DispBuff[RxLength++]=RUDR;
   
    }
  if(rtime<4)rtime++;//字节间隔时间,间隔3个字节重新开始一帧
  else RxLength=0;
  }
  
SIGNAL(SIG_INTERRUPT0)//INT0,边沿触发中断
  {
  unsigned char temp,temp2=0;
  static unsigned char pre_TCNT2,j=0;
  if(INT0_time==0)//一个字节第一个下降沿中断,起始位开始
    {
    TCNT2=130;
    pre_TCNT2=130;
    RUDR=0xff;//接收的数据初值
    j=0;  //位数清零
    INT0_time++;//中断次数加一
    }
  else
    {
    temp=TCNT2;
    if(temp>pre_TCNT2)temp2=temp-pre_TCNT2;//取一个高/低电平的宽度
    if(temp2>10)//滤过窄电平(干扰信号)
      {
      pre_TCNT2=temp;//记录前一次的时间值
      temp=0;
      while(temp2>13)//计算位的个数,约13为一个位(8*13=104uS)
          {
          temp2-=13;//
          temp++;
          }
      if(temp2>6)temp++;//计算位的个数,一般13为一个位
      if(INT0_time==1)temp-=1;
      if(INT0_time&1)//奇数次中断
        {
        while(temp)//位0的个数
          {
          RUDR&=~(1<<j);//相关位置0
          temp--;
          j++;
          }
        }
      else j+=temp;//偶数,位1的个数,跳过
      INT0_time++;//中断次数加一
      }
    }
  rtime=0;
  }
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友 微信微信
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|文字版|手机版|DIY编程器网 ( 桂ICP备14005565号-1 )

GMT+8, 2025-7-23 15:48 , 耗时 0.106811 秒, 19 个查询请求 , Gzip 开启.

各位嘉宾言论仅代表个人观点,非属DIY编程器网立场。

桂公网安备 45031202000115号

DIY编程器群(超员):41210778 DIY编程器

DIY编程器群1(满员):3044634 DIY编程器1

diy编程器群2:551025008 diy编程器群2

QQ:28000622;Email:libyoufer@sina.com

本站由桂林市临桂区技兴电子商务经营部独家赞助。旨在技术交流,请自觉遵守国家法律法规,一旦发现将做封号删号处理。

快速回复 返回顶部 返回列表