微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > PIC 单片机软件异步串行口实现技巧

PIC 单片机软件异步串行口实现技巧

时间:09-08 来源:互联网 点击:

/发送队列

unsigned char outPtr, //发送队列指针

outTotal, //发送的字节总数

chkSum; //发送的校验码

//=====================================================================

// 主程序

//=====================================================================

void main(void)

{

PORTA = 0;

PORTB = 0;

TRISB = 0b01; //输入输出定义

OPTION = 0b10000000; //TMR0选择内部指令周期计数

//TMR0预分频 1:2

rsRx.state = RS_IDLE; //初始化接收状态

rsTxBusy = 0; //发送空闲

INTCON = 0b00100000; //T0IE使能

GIE = 1; //打开中断

while(1) { //程序主循环

asm("clrwdt"); //清看门狗

UART_In(); //接收串行数据

UART_Out(); //发送串行数据

}

}

//=====================================================================

// 查询在接收FIFO队列中是否有新数据到

//然后解读数据

//=====================================================================

void UART_In(void)

{

unsigned char data1;

if (rsRx.putPtr==rsRx.getPtr)

return; //如果读取和存放的指针相同,则队列为空

data1 = rsRx.dataBuff[rsRx.getPtr]; //读取1个数据字节

rsRx.getPtr++; //调整读取指针到下一位置

rsRx.getPtr &= 0x07; //考虑环形队列回绕

//此处为数据解读分析,略

}

//=====================================================================

// 软件UART发送数据

//数据在outBuff中,outTotal为总字节数

//=====================================================================

void UART_Out(void)

{

if (rsTxBusy==1)

return; //正处于移位发送忙

//可以发送新数据

if (outTotal) { //如果有字节要发送

rsTx.shiftBuff = outBuff[outPtr++]; //取字节到发送移位寄存器

rsTxBusy = 1; //置发送忙标志,启动发送

outTotal--; //字节计数器减1

}

}

//===================================================================

// 中断服务程序

//===================================================================

void interrupt isr(void)

{

//利用TMR0 定时中断实现全双工软件UART

if (T0IE && T0IF) {

T0IF = 0; //清TMR0中断标志

//实现串行接收 RX 状态机控制

switch (rsRx.state) { //判当前接收状态

case RS_IDLE:

//当前状态为"空闲", 唯一要做的就是判"起始位"出现

if (RX_PIN==0) { //如果接收到低电平

rsRx.sliceCount = 4; //准备4*Ts时间间隔

rsRx.shiftCount = 8; //总共接收8位数据位

//改变此数值可以实现任意位数的数据接收

rsRx.state = RS_DATA_BIT; //切换到数据位接收状态

}

break;

case RS_DATA_BIT:

//当前状态为"数据接收"

if (--rsRx.sliceCount==0) { //等采样时间到

rsRx.shiftBuff >>= 1; //接收移位寄存器右移1位

if (RX_PIN) rsRx.shiftBuff|=0x80; //保存最新收到的数据位

rsRx.sliceCount = 3; //下次采样间隔为3*Ts

if (--rsRx.shiftCount==0) { //已经收到8位数据位?

//保存数据字节到FIFO缓冲队列

rsRx.dataBuff[rsRx.putPtr] = rsRx.shiftBuff;

//队列存放指针调整,最多8个字节缓冲

rsRx.putPtr = (rsRx.putPtr+1) & 0x07;

//转去下个状态,判停止位

rsRx.state = RS_STOP_BIT;

}

}

break;

case RS_STOP_BIT:

//当前状态为停止位判别(此程序没有判别)

if (--rsRx.sliceCount==0) { //等采样时间到

//此处可以判RX_PIN是否为1

rsRx.state = RS_IDLE; //复位接收过程

}

break;

default:

//异常处理

rsRx.state = RS_IDLE; //复位接收过程

}

//实现串行发送 TX 状态机控制

switch (rsTx.state) { //判当前发送状态

case RS_IDLE: //发送起始位

if (rsTxBusy) { //如果发送启动

TX_PIN = 0; //发出起始位低电平

rsTx.sliceCount = 3; //持续时间3*Ts

rsTx.shiftCount = 8; //数据位数为8位

rsTx.state = RS_DATA_BIT; //转去下一状态

} else TX_PIN = 1; //如果没有数据发送则保证数据线为空闲

break;

case RS_DATA_BIT: //发送8位数据位

if (--rsTx.sliceCount==0) { //码元宽度定时到

if (rsTx.shiftBuff & 0x01)//看数据位是0还是1

TX_PIN = 1; //发送1

else

TX_PIN = 0; //发送0

rsTx.shiftBuff >>= 1; //准备下次数据位发送

rsTx.sliceCount = 3; //数据位宽度为3*Ts

if (--rsTx.shiftCount==0) {

//8位数据位发送结束,转去发送停止位

rsTx.stat

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top