定时器中断轮流处理接收/发送端口的数据接收/发送工作,自然数据传输波特率为定时器中断频率的1/2。如有必要,定时器中断也可轮流处理更多端口的收发工作,以支持模拟更多串口,相应每个端口的数据处理速度也会进一步降低。
以下为程序文件:测试程序
/* ****************************************************************
* File name: main.c
* Function: AVR的I/O端口模拟串口测试程序
* Description: 1. 通过定时器中断轮流处理端口收发, 模拟UART数据收发功能
* 2. 外部晶振频率16.0MHz, 预分频值8, 定时器timer频率9600Hz,
* 定时器比较值207, 模拟串口波特率4800bps, 全双工异步模式,
* 支持模拟1个串口, 提高定时器频率或降低波特率, 1个定时器
可以支持模拟更多串口
* Author & Date: Joshua Chan, 2012/03/30
* ****************************************************************/
#include
#include
#include
#include
#include
#include "sim_uart_test.h"
/* 测试程序: 将接收的数据送出 */
void main(void)
{
unsigned char data;
var_init(); /* 初始化变量 */
port_init(); /* 配置收发端口 */
timer0_init(); /* 配置定时器 */
_SEI(); /* 全局中断使能 */
while (1) {
if ((data = rx_byte()) != NONE_DATA)
tx_byte(data);
_WDR();
}
}
/* ****************************************************************
* File name: sim_uart_test.h
* Function: AVR的I/O端口模拟串口测试程序
* Description: 1. 通过定时器中断轮流处理端口收发, 模拟UART数据收发功能
* 2. 外部晶振频率16.0MHz, 预分频值8, 定时器timer频率9600Hz,
* 定时器比较值207, 模拟串口波特率4800bps, 全双工异步模式,
* 支持模拟1个串口, 提高定时器频率或降低波特率, 1个定时器
可以支持模拟更多串口
* Author & Date: Joshua Chan, 2012/03/30
* ****************************************************************/
#ifndef _SIM_UART_TEST_H
#define _SIM_UART_TEST_H
/* PE0: 模拟UART接收端口
* PE1: 模拟UART发送端口
* PE0/PE1为硬件自带UART0的RX/TX口, 测试时需将其UART功能关闭
*/
#define GET_RX() (PINE & (1<
#define NONE_DATA '\4' /* 无新数据标志 */
/* 定义接收队列 */
#define RX_FIFO_SIZE 4 /* 接收队列大小 */
#define TX_FIFO_SIZE 4 /* 发送队列大小 */
/* 定时器中断发生时的读写周期 */
enum timer_turn {
RX_TURN = 0, /* 读周期 */
TX_TURN, /* 写周期 */
};
/* 数据帧结构 */
__flash enum frame_bit {
BIT_0 = 0,
BIT_1,
BIT_2,
BIT_3,
BIT_4,
BIT_5,
BIT_6,
BIT_7,
BIT_STOP,
BIT_IDLE,
BIT_START,
};
/* 变量初始化 */
extern void var_init(void);
/* 配置收发端口 */
extern void port_init(void);
/* 配置定时器 */
extern void timer0_init(void);
/* 从接收队列读1字节 */
extern unsigned char rx_byte(void);
/* 向发送队列写1字节 */
extern void tx_byte(unsigned char data);
#endif
/* ****************************************************************
* File name: sim_uart_test.c
* Function: AVR的I/O端口模拟串口测试程序
* Description: 1. 通过定时器中断轮流处理端口收发, 模拟UART数据收发功能
* 2. 外部晶振频率16.0MHz, 预分频值8, 定时器timer频率9600Hz,
* 定时器比较值207, 模拟串口波特率4800bps, 全双工异步模式,
* 支持模拟1个串口, 提高定时器频率或降低波特率, 1个定时器
可以支持模拟更多串口
* Author & Date: Joshua Chan, 2012/03/30
* ****************************************************************/
#include
#include
#include
#include
#include
#include "sim_uart_test.h"
unsigned char rx_fifo[RX_FIFO_SIZE]; /* 定义接收队列 */
unsigned char tx_fifo[TX_FIFO_SIZE]; /* 定义发送队列 */
unsigned char rx_pos; /* 队列中最后接收数据位置 */
unsigned char read_pos; /* 队列中最后读取数据位置 */
unsigned char tx_pos; /* 队列中最后发送数据位置 */
unsigned char write_pos; /* 队列中最后写入数据位置 */
unsigned char rx_buf; /* 接收字节缓冲 */
unsigned char tx_buf; /* 发送字节缓冲 */
volatile unsigned char rx_bit; /* 接收帧位计数 */
volatile unsigned char tx_bit; /* 发送帧位计数 */
volatile unsigned char current_turn; /* 轮流读写周期标志 */
/* 变量初始化 */
void var_init(void)
{
rx_pos = 0;
read_pos = 0;
tx_pos = 0;
write_pos = 0;
/* 定义初始收发位为空闲位 */
rx_bit = BIT_IDLE;
tx_bit = BIT_IDLE;
current_turn = RX_TURN;
}
/* 配置定时器 */
void timer0_init(void)
{
TCCR0 = ((1<
TCNT0 = 0;
}
/* 配置收发端口 */
void port_init(void)
{
UCSR0B = 0; /* 关闭PE0/PE1上的硬件UART */
DDRE &= ~(1 << DDE0); /* PE0输入 */
DDRE |= (1 << DDE1); /* PE1输出 */
}
/* 从接收队列读1字节 */
unsigned char rx_byte(void)
{
if (read_pos != rx_pos) {
if (++read_pos == RX_FIFO_SIZE)
read_pos = 0;
return rx_fifo[read_pos];
} else {
return NONE_DATA;
}
}
/* 向发送队列写1字节 */
void tx_byte(unsigned char data)
{
if (++write_pos == TX_FIFO_SIZE)
write_pos = 0;
tx_fifo[write_pos] = data;
}
/* 定时器读周期处理函数 */
static void rx_turn_isr(void)
{
switch (rx_bit) { /* 根据当前帧位执行相应操作 */
case BIT_IDLE:
if (!GET_RX()) /* 检测起始位, 以判断是否有数据待收 */
rx_bit = BIT_0;
break;
case BIT_0: /* 开始接收数据 */
case BIT_1:
case BIT_2:
case BIT_3:
case BIT_4:
case BIT_5:
case BIT_6:
case BIT_7:
if (GET_RX()) /* 根据端口电平, 写接收缓冲相应位 */
rx_buf |= (1 << rx_bit);
else
rx_buf &= ~(1 << rx_bit);
rx_bit++;
break;
case BIT_STOP:
if (GET_RX()) { /* 检测停止位, 出现帧错误则丢弃数据, 否则写入接收队列 */
if (++rx_pos == RX_FIFO_SIZE)
rx_pos = 0;
rx_fifo[rx_pos] = rx_buf;
}
rx_bit = BIT_IDLE;
break;
}
}
/* 定时器写周期处理函数 */
static void tx_turn_isr(void)
{
switch (tx_bit) { /* 根据当前帧位执行相应操作 */
case BIT_START:
CLR_TX(); /* 输出起始位 */
tx_bit = BIT_0;
break;
case BIT_0: /* 开始发送数据 */
case BIT_1:
case BIT_2:
case BIT_3:
case BIT_4:
case BIT_5:
case BIT_6:
case BIT_7:
if (tx_buf & (1 << tx_bit)) /* 根据待发数据位信息, 控制发送端电平 */
SET_TX();
else
CLR_TX();
tx_bit++;
break;
case BIT_STOP:
case BIT_IDLE:
SET_TX();
if (tx_pos != write_pos) { /* 检测是否有待发数据, 无则发送空闲位 */
if (++tx_pos == TX_FIFO_SIZE)
tx_pos = 0;
tx_buf = tx_fifo[tx_pos];
tx_bit = BIT_START;
} else {
tx_bit = BIT_IDLE;
}
break;
}
}
/* 定时器中断处理函数 */
#pragma vector = TIMER0_COMP_vect
__interrupt void timer0_isr(void)
{
switch (current_turn) {
case RX_TURN: /* 读周期 */
rx_turn_isr();
current_turn = TX_TURN;
break;
case TX_TURN: /* 写周期 */
tx_turn_isr();
current_turn = RX_TURN;
break;
}
}
上一篇:C51单片机和AVR单片机的区别
下一篇:编程点滴:AVR timer0 配置模块
推荐阅读最新更新时间:2024-03-16 15:16