AVR 328pb串口基本介绍和使用
-
📍相关篇《AVR 328pb定时器0基本介绍和使用》
-
🔖基于Atmel Studio 7.0开发环境。
-
📍结合参考同架构lgt8f328p中文文档:
http://www.prodesign.com.cn/wp-content/uploads/2023/03/LGT8FX8P_databook_v1.0.4.pdf
-
🪓工作模式下计算波特率(位/秒)以及UBRR值的公式。
波特率设置及引入误差
对于标准晶振及谐振器频率来说,异步模式下的实际通信的波特率可通过波特率计算公式来
获得,它与常用通信波特率之间的误差可用如下公式来计算:
Error[%] = (Baudreal/Baud – 1)*100%
其中,Baud为常用的通信波特率,Baudreal为通过计算公式算出来的波特率,带入波特率计
算公式即可得到波特率误差与系统时钟fsys和波特率寄存器UBRR值之间的关系如下:
普通模式:
Error[%] = (fsys/(16*(UBRR+1))/Baud – 1)*100%
倍速模式:
Error[%] = (fsys/(8*(UBRR+1))/Baud – 1)*100%
- 📄不同频率和波特率配置误差表:
- 当不考虑通信两边的时钟误差,即系统时钟 fsys为标准时钟时,即可得到波特率误差 UBRR值之间的关系。下表即为16MHz系统时钟下不同UBRR值设置下的波特率误差。
📗串口相关寄存器定义
-
UCSRA – USART 控制和状态寄存器A
-
UCSRB – USART控制和状态寄存器B
-
UCSRC– USART控制和状态寄存器C
-
🌿UBRR寄存器(包含:
UBRRnH
和UBRRnL
)
-
- UBRRnL – USART波特率寄存器低字节
- UBRRnL – USART波特率寄存器低字节
-
- UBRRnH – USART波特率寄存器高字节
- UBRRnH – USART波特率寄存器高字节
-
UDR – USART 数据寄存器
-
🌿串口参数代码具体配置:(基于Atmel Studio
GCC C Executable Project
裸机开发模式)
#define BAUD 9600
#define F_CPU 16000000UL
#define MYUBRR (F_CPU/16/BAUD-1)
// 串口初始化
void USART0_Init(void)
{
UCSR0A=(0<<RXC0) | (0<<TXC0) | (0<<UDRE0) | (0<<FE0) | (0<<DOR0) | (0<<UPE0) | (0<<U2X0) | (0<<MPCM0);
/*Enable receiver and transmitter */
UCSR0B=(1<<RXCIE0) | (0<<TXCIE0) | (0<<UDRIE0) | (1<<RXEN0) | (1<<TXEN0) | (0<<UCSZ02) | (0<<RXB80) | (0<<TXB80);
/* Set frame format: 8data, 1stop bit */
UCSR0C=(0<<UMSEL01) | (0<<UMSEL00) | (0<<UPM01) | (0<<UPM00) | (0<<USBS0) | (1<<UCSZ01) | (1<<UCSZ00) | (0<<UCPOL0);
/*Set baud rate */
UBRR0H = (unsigned char)(MYUBRR>>8);
UBRR0L = (unsigned char)MYUBRR;
stdout = &mystdout;//输出流配置
// Ensure that the USART0 is enabled
PRR0&= ~(1<<PRUSART0);
// Globally enable interrupts
sei();
}
- 🔖如果波特率倍频(X2):
#define BAUD 9600
#define F_CPU 16000000UL
#define MYUBRR (F_CPU/8/BAUD-1)
// 串口初始化
void USART0_Init(void)
{
// USART0 Baud Rate: 9600 (Double Speed Mode)
UCSR0A=(0<<RXC0) | (0<<TXC0) | (0<<UDRE0) | (0<<FE0) | (0<<DOR0) | (0<<UPE0) | (1<<U2X0) | (0<<MPCM0);
/*Enable receiver and transmitter */
UCSR0B=(1<<RXCIE0) | (0<<TXCIE0) | (0<<UDRIE0) | (1<<RXEN0) | (1<<TXEN0) | (0<<UCSZ02) | (0<<RXB80) | (0<<TXB80);
/* Set frame format: 8data, 1stop bit */
UCSR0C=(0<<UMSEL01) | (0<<UMSEL00) | (0<<UPM01) | (0<<UPM00) | (0<<USBS0) | (1<<UCSZ01) | (1<<UCSZ00) | (0<<UCPOL0);
/*Set baud rate */
UBRR0H = (unsigned char)(MYUBRR>>8);
UBRR0L = (unsigned char)MYUBRR;
stdout = &mystdout;//输出流配置
// Ensure that the USART0 is enabled
PRR0&= ~(1<<PRUSART0);
// Globally enable interrupts
sei();
}
- 🌿串口0数据发送函数:
void USART_Transmit( unsigned char data )
{
/* Wait for empty transmit buffer */
while ( !( UCSR0A & (1<<UDRE0)) )
;
/* Put data into buffer, sends the data */
UDR0 = data;
}
- 🌿串口0数据接收函数:
unsigned char USART_Receive( void )
{
/* Wait for data to be received */
while ( !(UCSR0A & (1<<RXC0)) )
;
/* Get and return received data from buffer */
return UDR0;
}
🔧printf打印配置内容
- (基于Atmel Studio
GCC C Executable Project
裸机开发模式)
#include "util/setbaud.h"
#include "avr/sfr_defs.h"//包含loop_until_bit_is_set函数
// Standard Input/Output functions
#include <stdio.h>
// 配置输出流
static FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL,
_FDEV_SETUP_WRITE);
//static FILE USART0_stream = FDEV_SETUP_STREAM(NULL, uart_getchar, _FDEV_SETUP_RW);//
static int uart_putchar(char c, FILE *stream)
{
// if (c == '\n')
// uart_putchar('\r', stream);
// loop_until_bit_is_set(UCSR0A, UDRE0);//需包含:avr/sfr_defs.h
// /* Wait for empty transmit buffer */
while ( !( UCSR0A & (1<<UDRE0)) );
UDR0 = c;
return 0;
}
📘串口0中断接收和printf打印例程
- 🔖(基于Atmel Studio
GCC C Executable Project
裸机开发模式)
/*
* USART0_TEST1.c
*
* Created: 2024/2/2 12:34:43
* Author : Administrator
*/
#include <avr/io.h>
#include "avr/interrupt.h"
#define BAUD 9600
#define F_CPU 16000000UL
#define MYUBRR F_CPU/16/BAUD-1
#include "util/setbaud.h"
#include "avr/sfr_defs.h"//包含loop_until_bit_is_set函数
// Standard Input/Output functions
#include <stdio.h>
//#include <stdlib.h>
#include "util/delay.h"
#include "string.h"
#define DATA_REGISTER_EMPTY (1<<UDRE0)
#define RX_COMPLETE (1<<RXC0)
#define FRAMING_ERROR (1<<FE0)
#define PARITY_ERROR (1<<UPE0)
#define DATA_OVERRUN (1<<DOR0)
// USART0 Receiver buffer
#define RX_BUFFER_SIZE0 16
char rx_buffer0[RX_BUFFER_SIZE0];
volatile unsigned char Rx_flag=0;
#if RX_BUFFER_SIZE0 < 256
volatile unsigned char rx_counter0=0;
#else
volatile unsigned int rx_counter0=0;
#endif
// This flag is set on USART0 Receiver buffer overflow
char rx_buffer_overflow0;
static int uart_putchar(char c, FILE *stream);
//static char uart_getchar(char c, FILE *stream);
// 配置输入输出流
static FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL,
_FDEV_SETUP_WRITE);
//static FILE USART0_stream = FDEV_SETUP_STREAM(NULL, uart_getchar, _FDEV_SETUP_RW);//
static int uart_putchar(char c, FILE *stream)
{
// if (c == '\n')
// uart_putchar('\r', stream);
// loop_until_bit_is_set(UCSR0A, UDRE0);//需包含:avr/sfr_defs.h
// /* Wait for empty transmit buffer */
while ( !( UCSR0A & (1<<UDRE0)) );
UDR0 = c;
return 0;
}
/*
static int uart_getchar(char c, FILE *stream)
{
char data;
// Wait for data to be received
while ( !(UCSR0A & (1<<RXC0)) )
data = UDR0;
return UDR0;
}
*/
// USART0 Receiver interrupt service routine串口0接收中断
ISR(USART0_RX_vect)
{
static volatile unsigned char status;
volatile char data;
status = UCSR0A;
data = UDR0;
if ((status & (FRAMING_ERROR | PARITY_ERROR | DATA_OVERRUN))==0)
{
rx_buffer0[rx_counter0++]=data;
if (rx_counter0 > 0&&(rx_buffer0[rx_counter0]==0))
{
// rx_counter0=0;
rx_buffer_overflow0=1;
}
}
}
// 串口初始化
void USART0_Init(void)
{
// USART0 initialization
// Communication Parameters: 8 Data, 1 Stop, No Parity
// USART0 Receiver: On
// USART0 Transmitter: On
// USART0 Mode: Asynchronous
// USART0 Baud Rate: 9600
cli();//关中断
UCSR0A=(0<<RXC0) | (0<<TXC0) | (0<<UDRE0) | (0<<FE0) | (0<<DOR0) | (0<<UPE0) | (0<<U2X0) | (0<<MPCM0);
/*Enable receiver and transmitter */
UCSR0B=(1<<RXCIE0) | (0<<TXCIE0) | (0<<UDRIE0) | (1<<RXEN0) | (1<<TXEN0) | (0<<UCSZ02) | (0<<RXB80) | (0<<TXB80);
/* Set frame format: 8data, 1stop bit */
UCSR0C=(0<<UMSEL01) | (0<<UMSEL00) | (0<<UPM01) | (0<<UPM00) | (0<<USBS0) | (1<<UCSZ01) | (1<<UCSZ00) | (0<<UCPOL0);
/*Set baud rate */
// UBRR0H=0x00;
// UBRR0L=0x67;//9600
UBRR0H = (unsigned char)(MYUBRR>>8);
UBRR0L = (unsigned char)MYUBRR;
// Ensure that the USART0 is enabled
PRR0&= ~(1<<PRUSART0);
stdout = &mystdout;
// Globally enable interrupts
sei();
}
int main(void)
{
/* Replace with your application code */
CLKPR=(1<<CLKPCE);
CLKPR=(0<<CLKPCE) | (0<<CLKPS3) | (0<<CLKPS2) | (0<<CLKPS1) | (0<<CLKPS0);
DDRB = PINB5;//配置PB5为输出模式
USART0_Init();
printf("Hello World!\r\n");
while (1)
{
if (rx_buffer_overflow0)
{
rx_counter0 =0;
rx_buffer_overflow0 =0;
printf("%s\r\n",rx_buffer0);
memset(rx_buffer0,0,sizeof(rx_buffer0));
}
PORTB ^= (1 << PINB5);//PB5状态翻转
_delay_ms(1000);
}
}
- 🎬串口测试效果:
🔰Atmel Studio Atmel Start Project
开发模式工程
✨如果基于Atmel Start Project创建对应的串口外设工程,那么开发方式如同STM32使用STM32CubeMX来配置工程并开发,相对于使用纯裸机自行配置寄存器开发方式要简单易上手一些。不需要掌握具体外设对应的寄存器如何配置信息。
🛠配置流程
- 创建
Atmel Start Project
创建工程。 - 选择对应的开发芯片型号。
- 添加对应的外设:
- 串口初始化函数:
USART_0_initialization();
/* configure pins and initialize registers */
void USART_0_initialization(void)
{
// Set pin direction to input
PD0_set_dir(PORT_DIR_IN);
PD0_set_pull_mode(
// <y> Pull configuration
// <id> pad_pull_config
// <PORT_PULL_OFF"> Off
// <PORT_PULL_UP"> Pull-up
PORT_PULL_OFF);
// Set pin direction to output
PD1_set_dir(PORT_DIR_OUT);
PD1_set_level(
// <y> Initial level
// <id> pad_initial_level
// <false"> Low
// <true"> High
false);
USART_0_init();
}
/**
* \brief Initialize USART interface
* If module is configured to disabled state, the clock to the USART is disabled
* if this is supported by the device's clock system.
*
* \return Initialization status.
* \retval 0 the USART init was successful
* \retval 1 the USART init was not successful
*/
int8_t USART_0_init()
{
// Module is in UART mode
/* Enable USART0 */
PRR0 &= ~(1 << PRUSART0);
#define BAUD 115200
#include <utils/setbaud.h>
UBRR0H = UBRRH_VALUE;
UBRR0L = UBRRL_VALUE;
UCSR0A = USE_2X << U2X0 /* */
| 0 << MPCM0; /* Multi-processor Communication Mode: disabled */
UCSR0B = 1 << RXCIE0 /* RX Complete Interrupt Enable: enabled */
| 0 << TXCIE0 /* TX Complete Interrupt Enable: disabled */
| 0 << UDRIE0 /* USART Data Register Empty Interupt Enable: disabled */
| 1 << RXEN0 /* Receiver Enable: enabled */
| 1 << TXEN0 /* Transmitter Enable: enabled */
| 0 << UCSZ02; /* */
// UCSR0C = (0 << UMSEL01) | (0 << UMSEL00) /* */
// | (0 << UPM01) | (0 << UPM00) /* Disabled */
// | 0 << USBS0 /* USART Stop Bit Select: disabled */
// | (1 << UCSZ01) | (1 << UCSZ00); /* 8-bit */
// UCSR0D = 0 << RXSIE /* USART RX Start Interrupt Enable: disabled */
// | 0 << SFDE; /* Start Frame Detection Enable: disabled */
#if defined(__GNUC__)
stdout = &USART_0_stream;
#endif
return 0;
}
- 👉通过
Atmel Start Project
创建的工程,配置的所有外设初始化都在atmel_start_init();
函数中被一起初始化。
- 测试代码:
#include <atmel_start.h>
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <stdio.h>
#include "string.h"
volatile uint16_t timer_overflow_count = 0;
#define DATA_REGISTER_EMPTY (1<<UDRE0)
#define RX_COMPLETE (1<<RXC0)
#define FRAMING_ERROR (1<<FE0)
#define PARITY_ERROR (1<<UPE0)
#define DATA_OVERRUN (1<<DOR0)
// USART0 Receiver buffer
#define RX_BUFFER_SIZE0 16
char rx_buffer0[RX_BUFFER_SIZE0];
volatile unsigned char Rx_flag=0;
#if RX_BUFFER_SIZE0 < 256
volatile unsigned char rx_counter0=0;
#else
volatile unsigned int rx_counter0=0;
#endif
// This flag is set on USART0 Receiver buffer overflow
char rx_buffer_overflow0;
// USART0 Receiver interrupt service routine
ISR(USART0_RX_vect)
{
static volatile unsigned char status;
volatile char data;
status = UCSR0A;
data = UDR0;
if ((status & (FRAMING_ERROR | PARITY_ERROR | DATA_OVERRUN))==0)
{
rx_buffer0[rx_counter0++]=data;
/*
#if RX_BUFFER_SIZE0 == 256
// special case for receiver buffer size=256
if (++rx_counter0 == 0) rx_buffer_overflow0=1;
#else
*/
// if (rx_wr_index0 == RX_BUFFER_SIZE0) rx_wr_index0=0;
if (rx_counter0 > 0&&(rx_buffer0[rx_counter0]==0))
{
// rx_counter0=0;
rx_buffer_overflow0=1;
}
//#endif
}
}
void delay_ms(uint16_t milliseconds)
{
while (milliseconds > 0)
{
_delay_ms(1); // 使用util/delay.h中的宏函数来实现1毫秒的延时
milliseconds--;
}
}
int main(void)
{
/* Initializes MCU, drivers and middleware */
atmel_start_init();
/* Replace with your application code */
while (1)
{
LED_set_level(false);
//delay_ms_timer(1000);
delay_ms(1000);
LED_set_level(true);
delay_ms(1000);
// delay_ms_timer(1000);
printf("Hello AVR Studio\r\n");
/*查看gcc版本信息*/
#ifdef __GNUC__
printf("__GNUC__ = %d\n",__GNUC__);
#endif
#ifdef __GNUC_MINOR__
printf("__GNUC_MINOR__ = %d\n",__GNUC_MINOR__);
#endif
#ifdef __GNUC_PATCHLEVEL__
printf("__GNUC_PATCHLEVEL__ == %d\n",__GNUC_PATCHLEVEL__);
#endif
}
if (rx_buffer_overflow0)//打印接收到的数据
{
rx_counter0 =0;
rx_buffer_overflow0 =0;
printf("%s\r\n",rx_buffer0);
memset(rx_buffer0,0,sizeof(rx_buffer0));
}
}