个人认为,AVR系列的串口使用还是比较容易出错,如果采用传统的查询方式太耗系统时间,而且现在关于AVR的教材大多给你的是查询发送方式,中断接收方式。
本例子是采用中断接收,中断发送方式。希望对大家有所帮助。
//ICC-AVR
// Target : M8
// Crystal: 4.0000Mhz
#include< iom8v.h>
#include< macros.h>
#define DISABLE_UARTTX() UCSRB&=~BIT(TXCIE)
#define ABLE_UARTTX() UCSRA|=BIT(TXC);UCSRB|=BIT(TXCIE)
unsigned char ucRecv;
unsigned char ucRecvOk;
unsigned char ucSendData[8]="Recv OK!";
unsigned char ucComSendCnt,ucComSendPtr;
void InitPort(void)
{
PORTB = 0xFF;
DDRB = 0x00;
PORTC = 0x7F; //m103 output only
DDRC = 0x00;
PORTD = 0xFE;
DDRD = 0x02;
}
//UART0 initialize
// desired baud rate: 2400
// actual: baud rate:2404 (0.2%)
void InitUart0(void)
{
UCSRB = 0x00; //disable while setting baud rate
UCSRA = 0x00;
UCSRC = BIT(URSEL) | 0x06;
UBRRL = 0x67; //set baud rate lo
UBRRH = 0x00; //set baud rate hi
UCSRB = 0x98;
}
#pragma interrupt_handler uart0_rx_isr:iv_USART0_RXC
void uart0_rx_isr(void)
{
unsigned char ucTmp;
//uart has received a character in UDR
ucTmp=UDR;
if (ucTmp=='A')
{
ucRecv=ucTmp;
ucRecvOk=0x01;
}
}
#pragma interrupt_handler uart0_tx_isr:iv_USART0_TXC
void uart0_tx_isr(void)
{
//character has been transmitted
if (ucComSendCnt!=0)
{
ucComSendPtr+=1;
UDR=ucSendData[ucComSendPtr];
ucComSendCnt-=1;
}else
{
//PORTB&=~BIT(PB_COM_LED); //串口指示灯灭
DISABLE_UARTTX();
//PORTB^=BIT(PB_COM_LED); //串口指示灯灭
}
}
//call this routine to initialize all peripherals
void InitMcu(void)
{
//stop errant interrupts until set up
CLI(); //disable all interrupts
InitPort();
InitUart0();
MCUCR = 0x00;
GICR = 0x00;
TIMSK = 0x00; //timer interrupt sources
SEI(); //re-enable interrupts
//all peripherals are now initialized
}
void main(void)
{
unsigned char i;
InitMcu();
while(1)
{
if (ucRecvOk==0x01)
{
CLI();
ucRecvOk=0;
SEI();
ucComSendCnt=7;
ucComSendPtr=0;
ABLE_UARTTX();
UDR=ucSendData[0];
}
}
}
本例子是采用中断接收,中断发送方式。希望对大家有所帮助。
//ICC-AVR
// Target : M8
// Crystal: 4.0000Mhz
#include< iom8v.h>
#include< macros.h>
#define DISABLE_UARTTX() UCSRB&=~BIT(TXCIE)
#define ABLE_UARTTX() UCSRA|=BIT(TXC);UCSRB|=BIT(TXCIE)
unsigned char ucRecv;
unsigned char ucRecvOk;
unsigned char ucSendData[8]="Recv OK!";
unsigned char ucComSendCnt,ucComSendPtr;
void InitPort(void)
{
PORTB = 0xFF;
DDRB = 0x00;
PORTC = 0x7F; //m103 output only
DDRC = 0x00;
PORTD = 0xFE;
DDRD = 0x02;
}
//UART0 initialize
// desired baud rate: 2400
// actual: baud rate:2404 (0.2%)
void InitUart0(void)
{
UCSRB = 0x00; //disable while setting baud rate
UCSRA = 0x00;
UCSRC = BIT(URSEL) | 0x06;
UBRRL = 0x67; //set baud rate lo
UBRRH = 0x00; //set baud rate hi
UCSRB = 0x98;
}
#pragma interrupt_handler uart0_rx_isr:iv_USART0_RXC
void uart0_rx_isr(void)
{
unsigned char ucTmp;
//uart has received a character in UDR
ucTmp=UDR;
if (ucTmp=='A')
{
ucRecv=ucTmp;
ucRecvOk=0x01;
}
}
#pragma interrupt_handler uart0_tx_isr:iv_USART0_TXC
void uart0_tx_isr(void)
{
//character has been transmitted
if (ucComSendCnt!=0)
{
ucComSendPtr+=1;
UDR=ucSendData[ucComSendPtr];
ucComSendCnt-=1;
}else
{
//PORTB&=~BIT(PB_COM_LED); //串口指示灯灭
DISABLE_UARTTX();
//PORTB^=BIT(PB_COM_LED); //串口指示灯灭
}
}
//call this routine to initialize all peripherals
void InitMcu(void)
{
//stop errant interrupts until set up
CLI(); //disable all interrupts
InitPort();
InitUart0();
MCUCR = 0x00;
GICR = 0x00;
TIMSK = 0x00; //timer interrupt sources
SEI(); //re-enable interrupts
//all peripherals are now initialized
}
void main(void)
{
unsigned char i;
InitMcu();
while(1)
{
if (ucRecvOk==0x01)
{
CLI();
ucRecvOk=0;
SEI();
ucComSendCnt=7;
ucComSendPtr=0;
ABLE_UARTTX();
UDR=ucSendData[0];
}
}
}
评分
用文心一言给他来个中文注释:
#include< iom8v.h> // 包含特定于ATmega8V或其他兼容AVR型号的头文件,提供寄存器定义等
#include< macros.h> // 包含宏定义,可能用于简化位操作或寄存器访问
// 定义宏来启用和禁用UART发送完成中断
#define DISABLE_UARTTX() UCSRB& = ~BIT(TXCIE) // 清除UCSRB寄存器中的TXCIE位,禁用UART发送完成中断
#define ABLE_UARTTX() UCSRA |= BIT(TXC); UCSRB |= BIT(TXCIE) // 设置UCSRA的TXC位和UCSRB的TXCIE位,准备发送并启用中断
// 全局变量,用于接收和发送数据
unsigned char ucRecv; // 接收到的字符
unsigned char ucRecvOk; // 接收标志,接收到特定字符时置位
unsigned char ucSendData[8]="Recv OK!"; // 要发送的数据
unsigned char ucComSendCnt, ucComSendPtr; // 发送计数器和指针
// 初始化GPIO端口
void InitPort(void)
{
PORTB = 0xFF; // 设置PORTB的所有位为高电平(具体功能取决于硬件连接)
DDRB = 0x00; // 设置PORTB为输入模式
PORTC = 0x7F; // 设置PORTC的部分位为高电平(假设m103为输出)
DDRC = 0x00; // 设置PORTC为输入模式
PORTD = 0xFE; // 设置PORTD的特定位为高电平
DDRD = 0x02; // 设置PORTD的特定位为输出模式
}
// 初始化UART0
// 设定波特率为2400,但实际可能略有偏差(如2404)
void InitUart0(void)
{
UCSRB = 0x00; // 在设置波特率时禁用UART
UCSRA = 0x00; // 清除UCSRA寄存器
UCSRC = BIT(URSEL) | 0x06; // 设置UCSRC寄存器以启用异步USART模式,并设置字符大小为8位
UBRRL = 0x67; // 设置波特率低位
UBRRH = 0x00; // 设置波特率高位
UCSRB = 0x98; // 启用接收器和发送器,设置接收中断使能
}
// UART接收中断服务例程
#pragma interrupt_handler uart0_rx_isr:iv_USART0_RXC
void uart0_rx_isr(void)
{
unsigned char ucTmp;
// UART已接收到一个字符
ucTmp = UDR; // 从UDR寄存器读取接收到的字符
if (ucTmp == 'A') // 如果接收到的字符是'A'
{
ucRecv = ucTmp; // 保存接收到的字符
ucRecvOk = 0x01; // 设置接收标志
}
}
// UART发送中断服务例程
#pragma interrupt_handler uart0_tx_isr:iv_USART0_TXC
void uart0_tx_isr(void)
{
// 字符已发送
if (ucComSendCnt != 0) // 如果还有字符需要发送
{
ucComSendPtr += 1; // 发送指针递增
UDR = ucSendData[ucComSendPtr]; // 发送下一个字符
ucComSendCnt -= 1; // 发送计数器递减
}
else
{
// 发送完成,禁用UART发送中断
DISABLE_UARTTX();
// 注释掉的代码可能用于控制串口指示灯
}
}
// 初始化微控制器所有外设
void InitMcu(void)
{
// 在设置完成前停止错误中断
CLI(); // 禁用所有中断
InitPort(); // 初始化GPIO端口
InitUart0(); // 初始化UART0
MCUCR = 0x00; // 清除MCU控制寄存器
GICR = 0x00; // 清除全局中断控制寄存器(注意:某些AVR型号可能没有GICR)
TIMSK = 0x00; // 清除定时器中断源掩码寄存器(此处用于确保没有定时器中断)
SEI(); // 重新启用中断
// 所有外设现已初始化完成
}
// 主函数
void main(void)
{
unsigned char i; // 未使用的变量,可能用于调试或保留
InitMcu(); // 初始化微控制器
while(1) // 无限循环
{
if (ucRecvOk == 0x01) // 如果接收到特定字符
{
CLI(); // 禁用中断
ucRecvOk = 0; // 清除接收标志
SEI(); // 重新启用中断
ucComSendCnt = 7; // 设置发送计数器
ucComSendPtr = 0; // 重置发送指针
ABLE_UARTTX(); // 准备发送并启用发送中断
UDR = ucSendData[0]; // 发送第一个字符以启动发送过程
}
}
}
#include< iom8v.h> // 包含特定于ATmega8V或其他兼容AVR型号的头文件,提供寄存器定义等
#include< macros.h> // 包含宏定义,可能用于简化位操作或寄存器访问
// 定义宏来启用和禁用UART发送完成中断
#define DISABLE_UARTTX() UCSRB& = ~BIT(TXCIE) // 清除UCSRB寄存器中的TXCIE位,禁用UART发送完成中断
#define ABLE_UARTTX() UCSRA |= BIT(TXC); UCSRB |= BIT(TXCIE) // 设置UCSRA的TXC位和UCSRB的TXCIE位,准备发送并启用中断
// 全局变量,用于接收和发送数据
unsigned char ucRecv; // 接收到的字符
unsigned char ucRecvOk; // 接收标志,接收到特定字符时置位
unsigned char ucSendData[8]="Recv OK!"; // 要发送的数据
unsigned char ucComSendCnt, ucComSendPtr; // 发送计数器和指针
// 初始化GPIO端口
void InitPort(void)
{
PORTB = 0xFF; // 设置PORTB的所有位为高电平(具体功能取决于硬件连接)
DDRB = 0x00; // 设置PORTB为输入模式
PORTC = 0x7F; // 设置PORTC的部分位为高电平(假设m103为输出)
DDRC = 0x00; // 设置PORTC为输入模式
PORTD = 0xFE; // 设置PORTD的特定位为高电平
DDRD = 0x02; // 设置PORTD的特定位为输出模式
}
// 初始化UART0
// 设定波特率为2400,但实际可能略有偏差(如2404)
void InitUart0(void)
{
UCSRB = 0x00; // 在设置波特率时禁用UART
UCSRA = 0x00; // 清除UCSRA寄存器
UCSRC = BIT(URSEL) | 0x06; // 设置UCSRC寄存器以启用异步USART模式,并设置字符大小为8位
UBRRL = 0x67; // 设置波特率低位
UBRRH = 0x00; // 设置波特率高位
UCSRB = 0x98; // 启用接收器和发送器,设置接收中断使能
}
// UART接收中断服务例程
#pragma interrupt_handler uart0_rx_isr:iv_USART0_RXC
void uart0_rx_isr(void)
{
unsigned char ucTmp;
// UART已接收到一个字符
ucTmp = UDR; // 从UDR寄存器读取接收到的字符
if (ucTmp == 'A') // 如果接收到的字符是'A'
{
ucRecv = ucTmp; // 保存接收到的字符
ucRecvOk = 0x01; // 设置接收标志
}
}
// UART发送中断服务例程
#pragma interrupt_handler uart0_tx_isr:iv_USART0_TXC
void uart0_tx_isr(void)
{
// 字符已发送
if (ucComSendCnt != 0) // 如果还有字符需要发送
{
ucComSendPtr += 1; // 发送指针递增
UDR = ucSendData[ucComSendPtr]; // 发送下一个字符
ucComSendCnt -= 1; // 发送计数器递减
}
else
{
// 发送完成,禁用UART发送中断
DISABLE_UARTTX();
// 注释掉的代码可能用于控制串口指示灯
}
}
// 初始化微控制器所有外设
void InitMcu(void)
{
// 在设置完成前停止错误中断
CLI(); // 禁用所有中断
InitPort(); // 初始化GPIO端口
InitUart0(); // 初始化UART0
MCUCR = 0x00; // 清除MCU控制寄存器
GICR = 0x00; // 清除全局中断控制寄存器(注意:某些AVR型号可能没有GICR)
TIMSK = 0x00; // 清除定时器中断源掩码寄存器(此处用于确保没有定时器中断)
SEI(); // 重新启用中断
// 所有外设现已初始化完成
}
// 主函数
void main(void)
{
unsigned char i; // 未使用的变量,可能用于调试或保留
InitMcu(); // 初始化微控制器
while(1) // 无限循环
{
if (ucRecvOk == 0x01) // 如果接收到特定字符
{
CLI(); // 禁用中断
ucRecvOk = 0; // 清除接收标志
SEI(); // 重新启用中断
ucComSendCnt = 7; // 设置发送计数器
ucComSendPtr = 0; // 重置发送指针
ABLE_UARTTX(); // 准备发送并启用发送中断
UDR = ucSendData[0]; // 发送第一个字符以启动发送过程
}
}
}