代码;
stduart.c
/*
《AVR专题精选》随书例程
3.通信接口使用技巧
项目:使用延时法实现半双工软件串口
文件:sfuart.c
说明:软件串口驱动文件
作者:邵子扬
时间:2012年12月13日
*/
#include "sfduart.h"
// 循环中延时调整系数
#define SFD_LOOP_VAR 12
// 软件串口初始化
void sfdUART_init(void)
{
PINDIR(sfdUART_TXDIO, PIN_OUTPUT);
PINSET(sfdUART_TXDIO);
PINDIR(sfdUART_RXDIO, PIN_INPUT);
PINSET(sfdUART_RXDIO);
}
// 读取一个字节
char sfdUART_getbyte(void)
{
unsigned char i, tmp;
// 起始位
while(PININ(sfdUART_RXDIO));
// 延时 1.5 比特位
_delay_us(1500000UL / sfdBAUDRATE);
// 读取8位数据
for(i = tmp = 0; i < 8; i++)
{
tmp = tmp >> 1;
if(PININ(sfdUART_RXDIO))
tmp |= 0x80;
// 循环中,延时函数需要调整时间,去掉循环语句本身占用时间
_delay_us(1000000UL / sfdBAUDRATE - SFD_LOOP_VAR);
}
// 1个停止位
_delay_us(1000000UL / sfdBAUDRATE);
return tmp;
}
// 发送一个字节
void sfdUART_sendbyte(char dat)
{
unsigned char i;
// 起始位
PINCLR(sfdUART_TXDIO);
_delay_us(1000000UL / sfdBAUDRATE);
// 8位数据位
for(i = 0; i < 8; i++)
{
if(dat & 0x01)
PINSET(sfdUART_TXDIO);
else
PINCLR(sfdUART_TXDIO);
dat = dat /2;
// 延时时间需要根据循环中指令数量进行调整
// 去掉指令占用时间,这个时间与指令数和时钟频率有关
_delay_us(1000000UL / sfdBAUDRATE - SFD_LOOP_VAR);
}
// 停止位
PINSET(sfdUART_TXDIO);
_delay_us(1000000UL / sfdBAUDRATE);
}
main.c
/*
《AVR专题精选》随书例程
3.通信接口使用技巧
项目:使用延时法实现半双工软件串口
文件:main.c
说明:软件串口的使用方法
作者:邵子扬
时间:2012年12月13日
*/
#include "cfg.h"
#include "macromcu.h"
#include "sfduart.h"
#include <avr/io.h>
// 计算波特率
#define UBRRREG (F_CPU / ( 8 * sfdBAUDRATE ) - 1)
const char msg[]="Input here> ";
// 初始化
void init()
{
int tmp;
// 初始化软件串口
sfdUART_init();
// 初始化硬件串口
// 使用硬件串口进行对比
UBRRH = UBRRREG / 256;
UBRRL = UBRRREG % 256;
UCSRA = ( 1 << U2X );
UCSRB = ( 1 << TXEN );
UCSRC = ( 1 << UCSZ1) | ( 1 << UCSZ0 );
// 显示提示消息
tmp = 0;
while(msg[tmp])
{
sfdUART_sendbyte(msg[tmp]);
tmp++;
}
}
int main(void)
{
char tmp;
init(); // 初始化
for(;;)
{
tmp = sfdUART_getbyte(); // 等待串口输入数据
UDR = tmp; // 发送到硬件串口
sfdUART_sendbyte(tmp); // 通过软件串口返回数据
// 可以对比两个串口的数据
// 以及波形
}
return 0;
}
仿真效果图