IO模擬UART

一橘蜜、 IO模擬UART發(fā)送

串口通信屬于 串行 異步 半雙工的通信模式

1、 最近在調(diào)試一個(gè)IO模擬UART的程序,把調(diào)試過程中遇到的問題總結(jié)一下。對(duì)于UART的發(fā)送部分(主機(jī)模式)還是比較容易實(shí)現(xiàn)的舞竿。比較麻煩的做從機(jī)時(shí),UART接收還在調(diào)試窿冯,可以接收數(shù)據(jù)骗奖,但還存在很多問題。

(1) 起始位:總線沒通信是高電平狀態(tài)醒串,要進(jìn)行通信時(shí)执桌,總線拉低發(fā)出“邏輯0”信號(hào),表示開始傳輸數(shù)據(jù)

(2) 數(shù)據(jù)位:通常以1byte數(shù)據(jù)為標(biāo)準(zhǔn)厦凤,從低位開始傳輸鼻吮,通過時(shí)鐘頻率來定位數(shù)據(jù)的傳輸

(3) 奇偶校驗(yàn)位:通過在數(shù)據(jù)末尾加上1位,使得數(shù)據(jù)包中的1的個(gè)數(shù)為偶數(shù)(偶校驗(yàn))或者是奇數(shù)(奇校驗(yàn))较鼓,來確定數(shù)據(jù)的準(zhǔn)確性椎木。

(4) 停止位:在通信結(jié)束時(shí)违柏,將總線拉高發(fā)出“邏輯1”信號(hào),表示傳輸結(jié)束香椎,也給下次進(jìn)行通信提供了校準(zhǔn)時(shí)間的機(jī)會(huì)

2漱竖、波特率

波特率表示每秒鐘傳送的碼元符號(hào)的個(gè)數(shù),是衡量數(shù)據(jù)傳輸速率的指標(biāo)畜伐,它用單位時(shí)間內(nèi)載波調(diào)制狀態(tài)改變的次數(shù)來表示馍惹,1波特即指每秒傳輸1個(gè)符號(hào)。

若 波特率為9600bps,那么傳輸一位數(shù)據(jù)的時(shí)間是在1000ms/9600bps=0.104ms

3玛界、串口發(fā)送數(shù)據(jù)組成

數(shù)據(jù)由:1bit起始位+8bit數(shù)據(jù)+1bit停止位構(gòu)成万矾;

所以,搞懂這些原理慎框,串口發(fā)送并不難良狈,主要把單片機(jī)的定時(shí)器配置在104us左右溢出中斷,保證每一位時(shí)間間隔在104us 左右即可笨枯。

我用的是51單片機(jī)薪丁,51本身自帶一個(gè)串口,但自己想用IO模擬一個(gè)串口出來馅精,便于自己更好的理解串口严嗜,也作為自己的一個(gè)技術(shù)儲(chǔ)備。



/**********************************************51單片機(jī)IO模擬UART實(shí)驗(yàn)************************************************************************************/

uart源文件

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

*文件名:uart.c

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

#include "reg52.h"

#include "type.h"

#include "uart.h"

#include "timer.h"

void UART_INIT(void)

{

? ? TX_D=1;

? ? Timer1Init();? ? //T1 初始化

}

void WAIT_TF1(void)

{

? ? while(!TF1);? //查詢計(jì)數(shù)器溢出標(biāo)志位

? ? TF1=0;

}

//寫數(shù)據(jù)很快的話洲敢,定時(shí)器不穩(wěn)定而導(dǎo)致發(fā)送的數(shù)據(jù)會(huì)有錯(cuò)碼漫玄,發(fā)送時(shí)應(yīng)適當(dāng)延時(shí)降低錯(cuò)碼概率

void Write_DATA(uint8_t input)

{

? ? uint8_t i=8;? //寫入1byte數(shù)據(jù)

? ? TR1=1;? ? ? ? //開始計(jì)時(shí)

? ? TX_D=0;? ? ? ? //拉低信號(hào)線準(zhǔn)備發(fā)送數(shù)據(jù)? 起始信號(hào)

? ? WAIT_TF1();? ? //106us溢出一次,溢出進(jìn)行下一位的傳輸

? ? while(i--)? ? //開始寫數(shù)據(jù)

? ? {

? ? ? ? TX_D=input&0X01;

? ? ? ? WAIT_TF1();

? ? ? ? input>>=1;

? ? }

? ? TX_D=1;? ? ? //8位數(shù)據(jù)發(fā)完拉高信號(hào)線? 停止信號(hào)

? ? WAIT_TF1();

? ? TR1=0;? ? ? ? //停止計(jì)時(shí)

}

//發(fā)送字符串

void Send_Char(uint8_t *buf)

{

? ? while(*buf != '\0')

? ? {

? ? Write_DATA(*buf);

? ? buf++;

? ? }

}

//發(fā)送數(shù)字

void Send_Num(uint8_t *buf,uint16_t s)

{

? ? while(s--)

? ? {

? ? ? ? Write_DATA(*buf+48);? ? //ASCII 將字符轉(zhuǎn)換成數(shù)字

? ? ? ? buf++;

? ? }

}

//發(fā)送多個(gè)數(shù)據(jù)

void Send_ND(uint8_t *buf,uint16_t len)

{

? ? while(len--)

? ? {

? ? ? ? Write_DATA(*buf);?

? ? ? ? buf++;

? ? }

}

uart頭文件

#include "type.h"

#ifndef? __UART_H__

#define? __UART_H__

sbit TX_D=P0^6;

extern uint8_t flag2;

extern void Send_Char(uint8_t *buf);? ? ? ? ? ? ? ? //發(fā)送字符

extern void Send_ND(uint8_t *buf,uint16_t len);? ? //發(fā)送N個(gè)數(shù)據(jù)

extern void Send_Num(uint8_t *buf,uint16_t s);? ? ? //發(fā)送數(shù)字

extern void UART_INIT(void);? ? ? ? ? ? ? ? ? ? ? ? //串口初始化

extern void WAIT_TF1(void);? ? ? ? ? ? ? ? ? ? ? ? //等待TF1溢出

extern void Write_DATA(uint8_t input);? ? ? ? ? ? ? //寫數(shù)據(jù)

#endif

timer源文件

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

文件名:timer.c

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

#include "reg52.h"

#include "type.h"

#include "timer.h"

uint8_t flag1=0;

void Timer1Init()

{

? TMOD = 0x10;? //T1? 方式1

? ? TH1 = 0xFF;? ? //波特率9600bps 1000ms/9600bps=0.104ms

? ? TL1 = 0xA0;? ? //定時(shí)器誤差2us左右? 106us

? ? EA = 1;

? ? ET1 = 1;

? ? TR1 = 1;

? TF1=0;

}

void Time1() interrupt 3

{

if(TR1==1)

{

TH1=0XFF;

TL1=0xA0;

flag1=1;

}

}

timer頭文件

#include "type.h"

#ifndef? __TIMER_H__

#define? __TIMER_H__

extern uint8_t flag1;

extern void Timer1Init(void);

#endif

type頭文件

#ifndef? __TYPE_H__

#define? __TYPE_H__

#define uint8_t? unsigned char

#define uint16_t? unsigned int

#endif

/*******************************************************主程序--測試部分****************************************************************/

#include "reg52.h"

#include "type.h"

#include "timer.h"

#include "uart.h"

#include "delay.h"

uint8_t buffer[5];

uint8_t Buff[5]={1,2,3,4,5};


void main(void)

{

UART_INIT();

Write_DATA('A');

Send_Char("testuart");

Send_Num(Buff,5);

while(1);

}

如果發(fā)送發(fā)在while(1)中跑的話压彭,需要加延時(shí)來降低由于查詢過快導(dǎo)致的發(fā)送亂碼的概率称近,事實(shí)證明加延時(shí)效果更好,結(jié)果更準(zhǔn)確哮塞。



二刨秆、 IO模擬UART接收

1、模擬串口接收部分是可以接收忆畅,但存在很多問題

2衡未、我對(duì)問題進(jìn)行了總結(jié)以便后期改進(jìn)

3、讀數(shù)據(jù)? 接收數(shù)據(jù)的效果不是很好家凯,需要連續(xù)的點(diǎn)擊發(fā)送字符才會(huì)成功

? ? 問題解析:估計(jì)是等到單片機(jī)掃描時(shí)缓醋,串口helper已經(jīng)把數(shù)據(jù)發(fā)送完了,單片機(jī)這邊對(duì)不上起始信號(hào)從而導(dǎo)致錯(cuò)峰绊诲,所以串口helper需要不停的點(diǎn)擊發(fā)送在這個(gè)期間對(duì)上了就進(jìn)去了送粱。

最近調(diào)試了一下,現(xiàn)在接收部分已經(jīng)可以正常接收了掂之。

接收部分

uint8_t Receive_Data(void)

{

uint8_t receive=0,t=0;

uint8_t i=8;

while(RX_D);? ? //等待起始信號(hào)抗俄,超時(shí)自動(dòng)退出

TR1=1;? ? //開始計(jì)時(shí)

WAIT_TF1();

while(i--)

{

receive>>=1;

if(RX_D)receive|=0x80;

WAIT_TF1();

}

TR1=0;

return receive;

}

void Recevice(uint8_t *temp,uint8_t data_size)? ?

{

while(data_size--)

{

*temp++=Receive_Data();

}

}

TEST

uint8_t recv[20]={0};

void main(void)

{

UART_INIT();

while(1)

{

? Recevice(recv,5);

? Send_ND(recv,5);

}

}

2020年11月17日

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末脆丁,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子动雹,更是在濱河造成了極大的恐慌槽卫,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,640評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件胰蝠,死亡現(xiàn)場離奇詭異歼培,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)茸塞,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,254評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門躲庄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人钾虐,你說我怎么就攤上這事读跷。” “怎么了禾唁?”我有些...
    開封第一講書人閱讀 165,011評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長无切。 經(jīng)常有香客問我荡短,道長,這世上最難降的妖魔是什么哆键? 我笑而不...
    開封第一講書人閱讀 58,755評(píng)論 1 294
  • 正文 為了忘掉前任掘托,我火速辦了婚禮,結(jié)果婚禮上籍嘹,老公的妹妹穿的比我還像新娘闪盔。我一直安慰自己,他們只是感情好辱士,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,774評(píng)論 6 392
  • 文/花漫 我一把揭開白布泪掀。 她就那樣靜靜地躺著,像睡著了一般颂碘。 火紅的嫁衣襯著肌膚如雪异赫。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,610評(píng)論 1 305
  • 那天头岔,我揣著相機(jī)與錄音塔拳,去河邊找鬼。 笑死峡竣,一個(gè)胖子當(dāng)著我的面吹牛靠抑,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播适掰,決...
    沈念sama閱讀 40,352評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼颂碧,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼荠列!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起稚伍,我...
    開封第一講書人閱讀 39,257評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤弯予,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后个曙,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體锈嫩,經(jīng)...
    沈念sama閱讀 45,717評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,894評(píng)論 3 336
  • 正文 我和宋清朗相戀三年垦搬,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了呼寸。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,021評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡猴贰,死狀恐怖对雪,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情米绕,我是刑警寧澤瑟捣,帶...
    沈念sama閱讀 35,735評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站栅干,受9級(jí)特大地震影響迈套,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜碱鳞,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,354評(píng)論 3 330
  • 文/蒙蒙 一桑李、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧窿给,春花似錦贵白、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,936評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至角撞,卻和暖如春圈浇,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背靴寂。 一陣腳步聲響...
    開封第一講書人閱讀 33,054評(píng)論 1 270
  • 我被黑心中介騙來泰國打工磷蜀, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人百炬。 一個(gè)月前我還...
    沈念sama閱讀 48,224評(píng)論 3 371
  • 正文 我出身青樓褐隆,卻偏偏與公主長得像,于是被迫代替她去往敵國和親剖踊。 傳聞我的和親對(duì)象是個(gè)殘疾皇子庶弃,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,974評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容