日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

单片机IO口模拟串口程序(发送+接收

發布時間:2023/12/31 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 单片机IO口模拟串口程序(发送+接收 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
單片機IO口模擬串口程序(發送+接收)【轉】 qcmc?發表于?-?2011-6-23 0:42:00
前一陣一直在做單片機的程序,由于串口不夠,需要用IO口來模擬出一個串口。經過若干曲折并參考了一些現有的資料,基本上完成了。現在將完整的測試程序,以及其中一些需要總結的部分貼出來。

程序硬件平臺:11.0592M晶振,STC單片機(兼容51)

/***************************************************************
*????在單片機上模擬了一個串口,使用P2.1作為發送端
*????把單片機中存放的數據通過P2.1作為串口TXD發送出去
***************************************************************/

#i nclude?<reg51.h>
#i nclude?<stdio.h>
#i nclude?<string.h>

typedef?unsigned?char?uchar;

int?i;

uchar?code?info[]?=?
{
0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55
};

sbit?newTXD?=?P2^1;//模擬串口的發送端設為P2.1

void?UartInit()
{
???? SCON??=?0x50;???//?SCON:?serail?mode?1,?8-bit?UART
???? TMOD?|=?0x21;???// T0工作在方式1,十六位定時
???? PCON?|=?0x80;???//?SMOD=1;
???? TH0??????=?0xFE;????//?定時器0初始值,延時417us,目的是令模擬串口的波特率為2400bps?fosc=11.0592MHz
????TL0???=?0x7F;????//?定時器0初始值,延時417us,目的是令模擬串口的波特率為2400bps?fosc=11.0592MHz

//????TH0??????=?0xFD;????//?定時器0初始值,延時417us,目的是令模擬串口的波特率為2400bps?fosc=18.432MHz
//????TL0???=?0x7F;????//?定時器0初始值,延時417us,目的是令模擬串口的波特率為2400bps?fosc=18.432MHz
}

void?WaitTF0(void)
{
???? while(!TF0);
???? TF0=0;
???? TH0=0xFE;????//?定時器重裝初值?fosc=11.0592MHz
???? TL0=0x7F;????//?定時器重裝初值?fosc=11.0592MHz

???? //????TH0??????=?0xFD;????//?定時器重裝初值?fosc=18.432MHz
???? //????TL0???=?0x7F;????//?定時器重裝初值?fosc=18.432MHz
}

void?WByte(uchar?input)
{
???? //發送啟始位
?????uchar?j=8;
???? TR0=1;
???? newTXD=(bit)0;
???? WaitTF0();
???? //發送8位數據位
?????while(j--)
???? {
???? ??? newTXD=(bit)(input&0x01);??????//先傳低位
?????????WaitTF0();
???? ??? input=input>>1;
???? }

???? //發送校驗位(無)

?????//發送結束位
?????newTXD=(bit)1;
???? WaitTF0();
???? TR0=0;
}????

void?Sendata()
{
???? for(i=0;i<sizeof(info);i++)//外層循環,遍歷數組
????{
???? ???? WByte(info[i]);
???? }
}

void?main()
{
???? UartInit();
???? while(1)
???? {
???? ???? Sendata();
???? }
}


##############################################################################


/***************************************************************
*???????模擬接收程序,這個程序的作用從模擬串口接收數據,然后將這些數據發送到實際串口
*????在單片機上模擬了一個串口,使用P3.2作為發送和接收端
*????以P3.2模擬串口接收端,從模擬串口接收數據發至串口
***************************************************************/

#i nclude<reg51.h>
#i nclude<stdio.h>
#i nclude<string.h>

typedef?unsigned?char?uchar?;

//這里用來切換晶振頻率,支持11.0592MHz和18.432MHz
//#define?F18_432
#define?F11_0592?
uchar?tmpbuf2[64]={0};
//用來作為模擬串口接收數據的緩存

struct?
{
???? uchar?recv?:6?;//tmpbuf2數組下標,用來將模擬串口接收到的數據存放到tmpbuf2中
?? ?? uchar?send?:6?;//tmpbuf2數組下標,用來將tmpbuf2中的數據發送到串口
}tmpbuf2_point={0,0};

sbit?newRXD=P3^2?;//模擬串口的接收端設為P3.2

void?UartInit()
{
???? SCON=0x50?;//?SCON:?serail?mode?1,?8-bit?UART
???? TMOD|=0x21?;//?TMOD:?timer?1,?mode?2,?8-bit?reload,自動裝載預置數(自動將TH1送到TL1);T0工作在方式1,十六位定時
???? PCON|=0x80?;//?SMOD=1;
????
???? #ifdef?F11_0592?
???? TH1=0xE8?;//?Baud:2400??fosc=11.0592MHz?2400bps為從串口接收數據的速率
???? TL1=0xE8?;//?計數器初始值,fosc=11.0592MHz?因為TH1一直往TL1送,所以這個初值的意義不大
???? TH0=0xFF?;//?定時器0初始值,延時208us,目的是令模擬串口的波特率為9600bps?fosc=11.0592MHz
?????? TL0=0xA0?;//?定時器0初始值,延時208us,目的是令模擬串口的波特率為9600bps?fosc=11.0592MHz
??????? #endif?

???? #ifdef?F18_432?
???? TH1=0xD8?;???? //?Baud:2400??fosc=18.432MHz?2400bps為從串口接收數據的速率
???? TL1=0xD8?;???? //?計數器初始值,fosc=18.432MHz?因為TH1一直往TL1送,所以這個初值的意義不大
??????? TH0=0xFF?;//?定時器0初始值,延時104us,目的是令模擬串口的波特率為9600bps?fosc=18.432MHz
??????? TL0=0x60?;//?定時器0初始值,延時104us,目的是令模擬串口的波特率為9600bps?fosc=18.432MHz
??????? #endif?

???? IE|=0x81?;//?中斷允許總控制位EA=1;使能外部中斷0
???? TF0=0?;
???? IT0=1?;//?設置外部中斷0為邊沿觸發方式
???? TR1=1?;//?啟動TIMER1,用于產生波特率
}

void?WaitTF0(void)
{
???? while(!TF0);
???? TF0=0?;

???? #ifdef?F11_0592?
???? TH0=0xFF?;//?定時器重裝初值?模擬串口的波特率為9600bps?fosc=11.0592MHz
???? TL0=0xA0?;//?定時器重裝初值?模擬串口的波特率為9600bps?fosc=11.0592MHz
???? #endif?

???? #ifdef?F18_432?
???? TH0=0xFF?;
???? //?定時器重裝初值?fosc=18.432MHz
???? TL0=0x60?;
???? //?定時器重裝初值?fosc=18.432MHz
???? #endif?
}

//接收一個字符
uchar?RByte()
{
???? uchar?Output=0?;
???? uchar?i=8?;
???? TR0=1?;???? //啟動Timer0
????
???? #ifdef?F11_0592?
???? TH0=0xFF?;//?定時器重裝初值?模擬串口的波特率為9600bps?fosc=11.0592MHz
???? TL0=0xA0?;//?定時器重裝初值?模擬串口的波特率為9600bps?fosc=11.0592MHz
???? #endif?

???? #ifdef?F18_432?
???? TH0=0xFF?;//?定時器重裝初值?fosc=18.432MHz
???? TL0=0x60?;//?定時器重裝初值?fosc=18.432MHz
???? #endif?

???? TF0=0?;

???? WaitTF0();//等過起始位
???? //接收8位數據位
???? while(i--)
???? {
???? ???? Output>>=1?;
???? ???? if(newRXD)Output|=0x80?;//先收低位
???????????? WaitTF0();//位間延時
???? }

???? TR0=0?;//停止Timer0
???? return?Output?;
}

//向COM1發送一個字符
void?SendChar(uchar?byteToSend)
{
???? SBUF=byteToSend?;
???? while(!TI);
???? TI=0?;
}

void?main()
{
???? UartInit();
???? while(1)
???? {
???? ???? if(tmpbuf2_point.recv!=tmpbuf2_point.send)//差值表示模擬串口接收數據緩存中還有多少個字節的數據未被處理(發送至串口)
???? ???? {
???? ???? ???? SendChar(tmpbuf2[tmpbuf2_point.send++]);
???? ???? }
???? }
}


//外部中斷0,說明模擬串口的起始位到來了
void?Simulated_Serial_Start()interrupt?0?
{
???? EX0=0?;???? //屏蔽外部中斷0
???? tmpbuf2[tmpbuf2_point.recv++]=RByte();???? //從模擬串口讀取數據,存放到tmpbuf2數組中
???? IE0=0?;???? //防止外部中斷響應2次,防止外部中斷函數執行2次
???? EX0=1?;???? //打開外部中斷0
}

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


以上是兩個獨立的測試程序,分別是模擬串口發送的測試程序和接收的測試程序
上面兩個程序在編寫過程中參考了這篇文章《51單片機模擬串口的三種方法》(在后文中簡稱《51》),但在它的基礎上做了一些補充,下面是若干總結的內容:

1、《51》在接收數據的程序中,采用的是循環等待的方法來檢測起始位(見《51》的附:51 IO口模擬串口通訊C源程序(定時器計數法) 部分),這種方法在較大程序中,可能會錯過起始位(比如起始位到來的時候程序正好在干別的,而沒有處于判斷起始位到來的狀態),或者一直在檢測起始位,而沒有辦法完成其他工作。為了避免這個問題,在本接收程序中采用了外部中斷的方法,將外部中斷0引腳作為模擬串口的接收端,設IT0=1(將外部中斷0設為邊緣觸發)。這樣當起始位(低電平)到來時,就會引發外部中斷,然后在外部中斷處理函數中接收余下的數據。這種方法可以保證沒數據的時候程序該干什么干什么,一旦模擬串口接收端有數據,就可以立即接收到。

2、加入了模擬串口接收緩沖區。在較大程序中,單片機要完成的工作很多,在模擬串口接收到了數據之后立即處理的話,有可能處理不過來造成丟失數據,或者影響程序其他部分執行。本程序中加入了64個字節的緩沖區,從模擬串口接收到的數據先存放在緩沖區中。這樣就算程序一時沒工夫處理這些數據,騰出手來之后也能在緩沖區中找到它們。

3、《51》文中的WByte函數和RByte函數中都先打開計數器后關閉計數器。如果使用本文的外部中斷法來接收數據,并且外部中斷處理函數里外都調用了WByte或RByte的話,需要將這兩個函數中的TR0=1,TR0=0操作的語句除去,并在UartInit()中加入一句TR0=1;即讓TR0始終開著就可以。
由于之前沒有意識到這個問題,因此在具體應用時出現了奇怪的問題:表現為中斷處理函數執行完畢之后,似乎回不到主程序,程序停在了一個不知道的地方。后來經過排查后找到了問題所在,那個程序的中斷處理函數中用了RByte,中斷處理函數外用到了WByte,而這兩個函數的最后都有TR0=0。這樣當中斷處理函數執行完畢后,TR0實際上是為0的,返回主程序后(中斷前的主程序可能正好處于其他的WByte或RByte執行中),原先以來定時器0溢出改變TF0才能執行下去的WByte函數就無法進行下去,從而導致整個程序停下來不動。(在本文的接收測試程序中不存在這個問題,因為中斷處理程序中雖調用了RByte,但中斷處理程序外卻沒有調用
RByte或WByte
下面是修改后的RByte、
WByte和WaitTF0函數,僅供參考:
/**********************************************
*????????????定時器0溢出后重裝初值
**********************************************/

void?WaitTF0(void)
{
???? TF0=0?;
???? #ifdef?F11_0592?
???? TH0=0xFF?;//?定時器重裝初值?fosc=11.0592MHz
???? TL0=0xA0?;//?定時器重裝初值?fosc=11.0592MHz
???? #endif?

???? #ifdef?F18_432?
???? TH0=0xFF?;//?定時器重裝初值?fosc=18.432MHz
???? TL0=0x60?;//?定時器重裝初值?fosc=18.432MHz
???? #endif?

???? while(!TF0);
???? TF0=0?;
}

/**********************************************
*????????????從串口B接收一個字符
**********************************************/

uchar?RByte()
{
???? uchar?Output=0?;
???? uchar?i=8?;
???? //????TR0=1;?????????????????????????????//啟動Timer0
/*
???? #ifdef?F11_0592
???? TH0??????=?0xFF;????//?定時器重裝初值?模擬串口的波特率為9600bps?fosc=11.0592MHz
???? TL0???=?0xA0;????//?定時器重裝初值?模擬串口的波特率為9600bps?fosc=11.0592MHz
???? #endif

???? #ifdef?F18_432
???? TH0??????=?0xFF;????//?定時器重裝初值?fosc=18.432MHz
???? TL0???=?0x60;????//?定時器重裝初值?fosc=18.432MHz
???? #endif
*/


???? WaitTF0();//等過起始位
????
???? //接收8位數據位
???? while(i--)
???? {
???? ???? Output>>=1?;
???? ???? if(newRXD)Output|=0x80?;???? ???? //先收低位
???????????? WaitTF0();//位間延時
???? }
???? //??while(!TF0)?if(newRXD)?break;????//此句和下一句不能加,如果加上了將導致耗時過長,影響下一個字節的接收
???? //????WaitTF0();????????????????????????//等過結束位
???? //????TR0=0;?????????????????????????????//停止Timer0
????
???? return?Output?;
}

/**********************************************
*????????????發送一個字節到串口B
**********************************************/

void?WByte(uchar?input)
{
???? //發送啟始位
???? uchar?j=8?;
???? //TR0=1;
???? newTXD=(bit)0?;
???? WaitTF0();
???? //發送8位數據位
???? while(j--)
???? {
???? ???? newTXD=(bit)(input&0x01);//先傳低位
???????????? WaitTF0();
???? ???? input=input>>1?;
???? }

???? //發送校驗位(無)

???? //發送結束位
???? newTXD=(bit)1?;
???? WaitTF0();
???? //TR0=0;
}

4、在上面的新修改后的
RByte()函數中,有被注釋掉的如下兩句:
//??while(!TF0)?if(newRXD)?break;????//此句和下一句不能加,如果加上了將導致耗時過長,影響下一個字節的接收
//????WaitTF0();????????????????????????//等過結束位

這兩句在《51》文中的程序是存在的,但是使用中斷接收法后,加上這兩句后出現了問題。表現為接收到的下一個字節的數據不完整或直接接收不到,似乎這兩句占用了過多的時間。
看這兩句的目的似乎是要延時以跳過結束位,但是我感覺這個結束位可以不用管它,反正結束位是個高電平,不會妨礙下一個字節是否到來的判斷(下一個字節的起始位是低電平)。那就由它去吧,沒有必要為了它而占用CPU的時間。
在本文的程序中,去掉這兩句后程序執行正確,如果其他朋友在使用時真的出現問題,可以試著再把它們加上試一下

轉載于:https://blog.51cto.com/2942350/607348

總結

以上是生活随笔為你收集整理的单片机IO口模拟串口程序(发送+接收的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 欧美丰满一区二区免费视频 | 国产精品久久久午夜夜伦鲁鲁 | 欧美人与物videos另类 | 亚洲激情另类 | 国内精品偷拍 | 亚洲在线观看免费视频 | 快色视频| 11孩岁女毛片 | 亚洲午夜久久久久久久久久久 | 无码av天堂一区二区三区 | 亚洲人免费 | 国产女主播喷水高潮网红在线 | 日韩视频一区二区 | 久久久久久久性 | 成年人免费网站在线观看 | 中文字幕人妻一区二区在线视频 | 久久精品国产亚洲av成人 | 欧美性xxxx | 香港日本韩国三级网站 | 在线国产视频一区 | 国产精品一区二区三区在线免费观看 | 91久久精品一区二区 | 免费久久av | 亚洲精品一区二区三区精华液 | 欧美福利片在线观看 | 欧美日韩精品一区二区在线观看 | 亚洲欧美日韩成人 | 久久黄色录像 | 欧美福利电影 | 欧美一级在线观看视频 | 欧美第九页 | 国产综合亚洲精品一区二 | 国产一级在线免费观看 | 精品在线观看一区二区 | 亚洲性图第一页 | 制服.丝袜.亚洲.中文.综合懂 | 欧美三级一区二区 | 亚洲第一字幕 | 老公吃小头头视频免费观看 | 久久精品aⅴ无码中文字字幕重口 | 秋霞在线一区二区 | 欧美性受xxxx白人性爽 | 少妇一级视频 | 国产女人视频 | 天天操国产 | 日韩欧美一区二区视频 | 日韩欧洲亚洲AV无码精品 | 成人少妇影院yyyy | 成人在线免费播放 | 午夜片在线观看 | 天天综合天天色 | 黄色二级毛片 | 欧美一区二区在线播放 | 日韩精选av| 国产成人高清 | 少妇名器的沉沦 | 日本色综合网 | 亚洲爽爽 | 亚洲欧美国产一区二区三区 | 日本精品一区二区三区视频 | 中文字幕在线播放不卡 | 国产精品免费视频一区 | 中文字幕久久网 | 狠狠躁夜夜躁xxxxaaaa | av男人的天堂av | 国产日韩欧美日韩大片 | 精品国产一区二区在线观看 | 色资源av| 欧美性大战久久久久久久蜜桃 | 精品一区二区在线视频 | 日本美女毛片 | 人人夜| 在线观看欧美一区二区 | 国产亚洲一区二区三区不卡 | 欧美精品一区二区三区视频 | 合欢视频污 | 精品蜜桃av | 国产毛片毛片毛片毛片毛片 | 在线视频97 | 日本夜夜操 | 亚洲精品动漫在线观看 | 久久国产精品网站 | 欧美人与性动交α欧美片 | 神马午夜不卡 | 成人激情视频在线观看 | 日本激情电影 | a级小视频 | 国产成人精品777777 | 国产稀缺真实呦乱在线 | 高清二区| 一本久久久 | 无码h黄肉3d动漫在线观看 | 欧美性生活精品 | 人人看超碰 | 丰满少妇在线观看资源站 | 美女日批在线观看 | 成人福利视频网站 | 一区二区三区 日韩 | 色婷婷视频在线观看 |