機電之家資源網(wǎng)
單片機首頁|單片機基礎|單片機應用|單片機開發(fā)|單片機文案|軟件資料下載|音響制作|電路圖下載 |嵌入式開發(fā)
培訓信息
贊助商
51單片機IO口模擬串口通訊C源程
51單片機IO口模擬串口通訊C源程
 更新時間:2009-9-11 16:43:13  點擊數(shù):0
【字體: 字體顏色

51 IO口模擬串口通訊C源程
#include <reg51.h>
sbit BT_SND =P1^0;
sbit BT_REC =P1^1;
/**********************************************

IO 口模擬232通訊程序

使用兩種方式的C程序 占用定時器0

**********************************************/

#define MODE_QUICK

#define F_TM F0

#define TIMER0_ENABLE TL0=TH0; TR0=1;
#define TIMER0_DISABLE TR0=0;

sbit ACC0= ACC^0;
sbit ACC1= ACC^1;
sbit ACC2= ACC^2;
sbit ACC3= ACC^3;
sbit ACC4= ACC^4;
sbit ACC5= ACC^5;
sbit ACC6= ACC^6;
sbit ACC7= ACC^7;

void IntTimer0() interrupt 1
{
F_TM=1;
}
//發(fā)送一個字符
void PSendChar(unsigned char inch)
{
#ifdef MODE_QUICK
ACC=inch;

F_TM=0;
BT_SND=0; //start bit
TIMER0_ENABLE; //啟動
while(!F_TM);

BT_SND=ACC0; //先送出低位
F_TM=0;
while(!F_TM);

BT_SND=ACC1;
F_TM=0;
while(!F_TM);

BT_SND=ACC2;
F_TM=0;
while(!F_TM);

BT_SND=ACC3;
F_TM=0;
while(!F_TM);

BT_SND=ACC4;
F_TM=0;
while(!F_TM);

BT_SND=ACC5;
F_TM=0;
while(!F_TM);

BT_SND=ACC6;
F_TM=0;
while(!F_TM);

BT_SND=ACC7;
F_TM=0;
while(!F_TM);

BT_SND=1;
F_TM=0;
while(!F_TM);


TIMER0_DISABLE; //停止timer
#else
unsigned char ii;

ii=0;

F_TM=0;
BT_SND=0; //start bit
TIMER0_ENABLE; //啟動
while(!F_TM);

while(ii<8)
{
if(inch&1)
{
BT_SND=1;
}
else
{
BT_SND=0;
}
F_TM=0;
while(!F_TM);
ii++;
inch>>=1;
}
BT_SND=1;
F_TM=0;
while(!F_TM);

#endif
TIMER0_DISABLE; //停止timer
}
//接收一個字符
unsigned char PGetChar()
{
#ifdef MODE_QUICK

TIMER0_ENABLE;
F_TM=0;
while(!F_TM); //等過起始位
ACC0=BT_REC;

TL0=TH0;

F_TM=0;
while(!F_TM);
ACC1=BT_REC;

F_TM=0;
while(!F_TM);
ACC2=BT_REC;

F_TM=0;
while(!F_TM);
ACC3=BT_REC;

F_TM=0;
while(!F_TM);
ACC4=BT_REC;

F_TM=0;
while(!F_TM);
ACC5=BT_REC;

F_TM=0;
while(!F_TM);
ACC6=BT_REC;

F_TM=0;
while(!F_TM);
ACC7=BT_REC;

F_TM=0;

while(!F_TM)
{
if(BT_REC)
{
break;
}
}
TIMER0_DISABLE; //停止timer
return ACC;
#else
unsigned char rch,ii;
TIMER0_ENABLE;
F_TM=0;
ii=0;
rch=0;
while(!F_TM); //等過起始位

while(ii<8)
{
rch>>=1;
if(BT_REC)
{
rch|=0x80;
}
ii++;
F_TM=0;
while(!F_TM);

}
F_TM=0;
while(!F_TM)
{
if(BT_REC)
{
break;
}

}
TIMER0_DISABLE; //停止timer
return rch;

#endif

}

AVR軟件模擬串口程序



 

M48,8MHz
9600,1,8,1

輸出:用定時器控制普通IO口輸出位
輸入:用外部中斷+定時器,判斷位的寬度

好幾天沒休息,利用閑暇寫的,也沒找到別人的參考程序,不過終于算是穩(wěn)定了,其實還應該有很多其它的方法可以試一下,比如用PWM輸出串行數(shù)據(jù),用輸入捕獲接收數(shù)據(jù),或定時查詢,或用任意一個IO口中斷,則每個引腳都有可能

現(xiàn)在還有些問題,全雙工同時收發(fā)時發(fā)送偶爾出錯,占用兩個定時器有些浪費,以后再修改吧,最好加上各種波率

本程序為直接摘出部分,刪了無關的部分,在此可能有些變量沒用,或有段落遺漏,請諒

#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,                //中斷次數(shù)

RxLength=0,        //接收長度
RUDR,            //摸擬串口接收的數(shù)據(jù)
TxLength,                    //串口發(fā)送數(shù)據(jù)長度
SUDR;                        //串口發(fā)送的數(shù)據(jù)

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);//邊沿觸發(fā)
     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); //系統(tǒng)頻率/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();
}


/*啟動串口發(fā)送*/
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))//收到數(shù)據(jù)延時10mS后啟動發(fā)送,回送驗證數(shù)據(jù)
            {
            key=0;
            SendData(&DispBuff[0],9);//發(fā)送DispBuff[0]的9位數(shù)據(jù)
            while(TxLength);//等待發(fā)送完成
            rdata=0;
            eep_ms=0;
            }
        }
    }


/*定時器0,100us溢出中斷*/
SIGNAL(SIG_OVERFLOW0)
    {
    TCNT0=151;//重載數(shù)據(jù),計時區(qū)間為151---255,共104uS,一個位的時間
    if(TxLength)//
        {
        if(start==0)
            {
            Sbit0();//起始位
            SUDR=*(TxPoint++);
            }
        else
            {
            if((start<=8))
                {
                if(SUDR&(1<<(start-1)))Sbit1();//數(shù)據(jù)1
                else Sbit0();//數(shù)據(jù)0
                }
            else Sbit1();//停止位
            }
        if(start<10)start++;
        else
            {
            TxLength--;//一字節(jié) 發(fā)送完成,字節(jié)數(shù)減1
            start=0;
            }//
        }
    }

/*定時器1,1ms溢出中斷*/
SIGNAL(SIG_OVERFLOW1)
{
    eep_ms++;
}
/*定時器2*/
SIGNAL(SIG_OVERFLOW2)
    {
    sei();    
    if(INT0_time)//有數(shù)據(jù)
        {
        INT0_time=0;//中斷次數(shù)清0
        rdata=1;//置有數(shù)據(jù)標志
        eep_ms=0;
        if(RxLength<10)DispBuff[RxLength++]=RUDR;
        
        }
    if(rtime<4)rtime++;//字節(jié)間隔時間,間隔3個字節(jié)重新開始一幀
    else RxLength=0;
    }
    
SIGNAL(SIG_INTERRUPT0)//INT0,邊沿觸發(fā)中斷
    {
    unsigned char temp,temp2=0;
    static unsigned char pre_TCNT2,j=0;
    if(INT0_time==0)//一個字節(jié)第一個下降沿中斷,起始位開始
        {
        TCNT2=130;
        pre_TCNT2=130;
        RUDR=0xff;//接收的數(shù)據(jù)初值
        j=0;    //位數(shù)清零
        INT0_time++;//中斷次數(shù)加一
        }
    else
        {
        temp=TCNT2;
        if(temp>pre_TCNT2)temp2=temp-pre_TCNT2;//取一個高/低電平的寬度
        if(temp2>10)//濾過窄電平(干擾信號)
            {
            pre_TCNT2=temp;//記錄前一次的時間值
            temp=0;
            while(temp2>13)//計算位的個數(shù),約13為一個位(8*13=104uS)
                    {
                    temp2-=13;//
                    temp++;
                    }
            if(temp2>6)temp++;//計算位的個數(shù),一般13為一個位
            if(INT0_time==1)temp-=1;
            if(INT0_time&1)//奇數(shù)次中斷
                {
                while(temp)//位0的個數(shù)
                    {
                    RUDR&=~(1<<j);//相關位置0
                    temp--;
                    j++;
                    }
                }
            else j+=temp;//偶數(shù),位1的個數(shù),跳過
            INT0_time++;//中斷次數(shù)加一
            }
        }
    rtime=0;
    }

串囗模擬



 

;***********************************************************
;普通IO口模擬RS232串口  占用定時器0中斷
;在TH0,TL0中設置波特率的大小 注意不要開定時器0的中斷,這里用的是查詢方式;***********************************************************

BT_REC BIT P1.2
BT_SND BIT  P1.5
        ;占用定時器0
ORG 0000H
AJMP MAIN
main: MOV SP,#59H

RS232: MOV      TMOD,#02 ;利用定時器方式0
MOV      PCON,#80H
        ;****************************************************
        ;9600bps 就是 1000000/9600=104.167微秒
        ;執(zhí)行的timer是104.167*11.0592/12= 96 256-96=160(0A0H)
        ;執(zhí)行的timer是104.167*22.1184/12= 192 256-192=64(040H)

        ;19200bps 就是 1000000/19200=52.083微秒
        ;執(zhí)行的timer是52.083*11.0592/12= 48 256-48=208(0D0H)
        ;執(zhí)行的timer是52.083*22.1184/12= 96 256-96=160(0A0H)

        ;115200bps 就是 1000000/115200=8.6806微秒 (可能出錯,達不到那么高)
        ;執(zhí)行的timer是8.6806*11.0592/12= 8  256- 8=248(0F8H)
        ;執(zhí)行的timer是8.6806*22.1184/12= 16 256-16=240(0F0H)

        ;所以,改變TH0,TL0的處置就是改變了波特率
        ;****************************************************
MOV      TH0,#0A0H
MOV      TL0,#0A0H
SETB TR0  ;開定時器0
;============發(fā)送==============

MOV      A,#55H
LCALL    S_Char
MOV      A,#56H
LCALL    S_Char
MOV      A,#77H
LCALL    S_Char
AJMP JIESHU

;============接收=============
STAR: JB      BT_REC,$ ;檢測是否有開始位
LCALL   G_Char
MOV 30H,A  ;存儲接受來的數(shù)據(jù)
STAR0: JB      BT_REC,$ ;檢測是否有開始位
LCALL   G_Char
MOV 31H,A
JIESHU: NOP
AJMP JIESHU

;==============子程序=======================


;----------接收1個字節(jié)-------
;接收來的數(shù)在A中
;用到的資源:TF0,ACC,R7,TR0,TL0,TR0
G_Char: MOV      TL0,TR0
SETB     TR0
MOV  R7,#08H
R_LOOP: CLR      TF0 ;等待TIMER0的中斷TIMER0中斷的時間定了那么波特率也就定了
JNB      TF0,$
MOV      C,BT_REC
RRC  A
DJNZ  R7,R_LOOP
CLR      TF0
ST_BIT: JB       TF0,SADA  ;等待停止位
JNB      BT_REC,ST_BIT
SADA: CLR      TR0
RET

;---------發(fā)送1個字節(jié)------------
;要發(fā)送的數(shù)存在R7中
;用到的資源:R7,A,TF0,TRO,TL0,TR0
S_Char: CLR      TF0
CLR      BT_SND
MOV  R7,#08H
MOV      TL0,TR0
SETB     TR0
LOOP: JNB  TF0,$  ;判斷定時器是否溢出
RRC  A
MOV  BT_SND,C
CLR  TF0
DJNZ  R7,LOOP
JNB  TF0,$
SETB  BT_SND
CLR  TF0
JNB  TF0,$
CLR  TR0
RET

  • 上一篇: 用SPCE061A設計的嵌入式語音通信平臺
  • 下一篇: 沒有了
  • 發(fā)表評論   告訴好友   打印此文  收藏此頁  關閉窗口  返回頂部
    熱點文章
     
    推薦文章
     
    相關文章
    網(wǎng)友評論:(只顯示最新5條。)
    關于我們 | 聯(lián)系我們 | 廣告合作 | 付款方式 | 使用幫助 | 機電之家 | 會員助手 | 免費鏈接

    點擊這里給我發(fā)消息66821730(技術(shù)支持)點擊這里給我發(fā)消息66821730(廣告投放) 點擊這里給我發(fā)消息41031197(編輯) 點擊這里給我發(fā)消息58733127(審核)
    本站提供的機電設備,機電供求等信息由機電企業(yè)自行提供,該企業(yè)負責信息內(nèi)容的真實性、準確性和合法性。
    機電之家對此不承擔任何保證責任,有侵犯您利益的地方請聯(lián)系機電之家,機電之家將及時作出處理。
    Copyright 2007 機電之家 Inc All Rights Reserved.機電之家-由機電一體化網(wǎng)更名-聲明
    電話:0571-87774297 傳真:0571-87774298
    杭州濱興科技有限公司提供技術(shù)支持

    主辦:杭州市高新區(qū)(濱江)機電一體化學會
    中國行業(yè)電子商務100強網(wǎng)站

    網(wǎng)站經(jīng)營許可證:浙B2-20080178-1