ningkefan 发表于 2010-3-16 09:48:17

一个定时器实现全双功模拟串口

转载
设计原理:
本文通信波特率为9600bps,使用一个定时器(频率38400Hz)
通过3次分频为TX和RX二个通道同时提供准确的时钟驱动。RX不需要使
用外部中断,直接由定时器进行IO扫描。
设计模式:
异步操作模式。
试验环境:
ATMEGA16(L),16MHz外部晶振。
试验结果:
经过24小时不间断随机数据测试无一错误。
后期扩展:
提供更高的时钟支持更多的串口同时扫描。
#include <API/TYPEDEF.H> //类型定义
//IO
定义
#define GPRS_SET_TX() PORTD |= (1<<1)
#define GPRS_CLR_TX() PORTD &= ~(1<<1)
#define GPRS_PIN_RX (PIND & 1)
//38400Hz
时钟
#define TIMEBASE 0xFE0D
//
为RX
提供32
字节的FIFO
支持
#define MAX_FIFO 32
static BYTE ReceiveFIFO[
MAX_FIFO];
static BYTE FIFOI,
FIFOT;
extern WORD TIMEBASE;
extern BYTE TX_TIME;
static BYTE RXBIT,
RXCOUNT,
RXBUF;
static BYTE TXBIT,
TXBUF;
//
初始化
void UartInit(
void)
{
////////////////////////////////////////////////////////////////////
RXBIT =
0;
RXCOUNT =
1;
FIFOI =
0;
FIFOT =
0;
////////////////////////////////////////////////////////////////////
//配置IO模式
DDRD |=
(
1<<
1);
//TX PD1
DDRD &=
~
1;
//RX PD0
AVR 模拟串口林珍文
}
//
发送一个字节
void WriteByte(
BYTE value)
{
TXBUF =
value;
TXBIT =
0;
while ((
TXBIT &
0x80)
==
0);
}
//
发送一个字符串
void WriteStr(
char *
str)
{
while (*
str)
GPRS_WriteByte(*
str++);
}
//
获取RX
FIFO
收到的长度
BYTE GetFIFOCount(
void)
{
if (
FIFOI ==
FIFOT)
return 0;
if (
FIFOI >
FIFOT)
return FIFOI -
FIFOT;
return (
MAX_FIFO -
FIFOT)
+
FIFOI;
}
//
从RX
FIFO
中获取一个字节
BYTE ReadByte(
void)
{
BYTE RET =
ReceiveFIFO[
FIFOT++];
if (
FIFOT>
MAX_FIFO-
1)
FIFOT =
0;
return RET;
}
//AVR
Time
中断函数
//
注意为了保证代码在限定的时间下顺利执行完成,应尽量减少使用乘除法.
#pragma interrupt_handler timer1_ovf_isr:9
void timer1_ovf_isr(
void)
{
char RXB =
GPRS_PIN_RX;
TCNT1H =
TIMEBASE/
256;
//setup
TCNT1L =
TIMEBASE%
256;
////////////////////////////////////////////////////////////////////
//接收部分
if (
RXBIT &
0x80)
{
//判断是否接收完成
if (
RXB)
RXBIT =
0;
}
else
if (
RXBIT==
0 &&
RXB==
0)
{
//接收起始位
RXBIT =
RXCOUNT;
RXBUF =
0;
}
else
if ((
RXCOUNT ==
(
RXBIT &
3))
&&
(
RXBIT))
{
//接收8位数据
BYTE rxbitpos =
(
RXBIT>>
2);
switch (
rxbitpos)
AVR 模拟串口林珍文
{
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
RXBUF>>=
1;
if (
RXB)
RXBUF |=
0x80;
RXBIT =
(
RXBIT &
3)
|
((
rxbitpos+
1)<<
2);
break;
case 7:
//接收第8位,并直接处理结束位。
RXBUF>>=
1;
if (
RXB)
{
RXBUF |=
0x80;
RXBIT =
0;
}
else RXBIT =
0x80;
////////////////////////////////////////////////////////////////////
//接数据存放入FIFO
ReceiveFIFO[
FIFOI++]
=
RXBUF;
if (
FIFOI >
MAX_FIFO-
1)
FIFOI =
0;
break;
}
}
if (
RXCOUNT==
3)
RXCOUNT =
1;
else RXCOUNT++;
////////////////////////////////////////////////////////////////////
//发送部分
if (
TX_TIME==
2)
{
if ((
TXBIT &
0x80)==
0)
{
switch (
TXBIT)
{
case 0:
GPRS_CLR_TX();
//发送起始位
break;
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
if (
TXBUF &
1)
GPRS_SET_TX();
else GPRS_CLR_TX();
TXBUF>>=
1;
break;
case 9:
GPRS_SET_TX();
//发送结束位
break;
case 10:
//为每个字节增一个发送间隙
TXBIT |=
0x80;
break;
}
TXBIT++;
AVR 模拟串口林珍文
}
PORTD |=
(
1<<
2);
TX_TIME =
0;
}
else
{
PORTD &=
~(
1<<
2);
TX_TIME++;
}
}
点击此处下载 ourdev_538600.pdf(文件大小:128K) (原文件名:模拟串口.pdf)

jiaweiqiang 发表于 2010-8-13 11:37:42

hpdell 发表于 2011-1-22 12:16:09

顶!!!!!!!!!!!!!!!!!

lionlike 发表于 2011-6-5 15:49:08

mark

huangpeifeng 发表于 2012-9-7 19:53:26

mark{:sad:}{:sad:}

richwen 发表于 2012-9-17 13:44:04

好样的!

ZL88 发表于 2013-3-4 10:36:44

顶起来mark!

linjpxt 发表于 2013-3-4 10:50:02

如果处理器足够快,软解can都行,只是现在多串口的片子多去,这个做法效率太低了,不值得

ZL88 发表于 2013-3-7 11:43:12

楼主这个里面       
        PORTD |=(1<<2);
                TX_TIME =0;
        }
        else
        {
                PORTD &=~(1<<2);
                TX_TIME++;

PORTD |=(1<<2);
PORTD &=~(1<<2);是做什么用的?

zcx2012 发表于 2013-3-7 11:56:48

正好要用双串口
页: [1]
查看完整版本: 一个定时器实现全双功模拟串口