AVR串口
芯片:ATmega168P
晶振:8M
两种方法:
方法一:
1. 使用<stdio.h>定义的scanf和printf()输入输出数据
优点:使用非常方便
缺点:占用ROM和RAM空间比较多
(1)定义输入输出函数
#include <stdio.h>
// 从串口输出一个字符
static int uart_putchar(char c, FILE *stream)
{
if (c == '\n')
uart_putchar('\r', stream);
loop_until_bit_is_set(UCSR0A, UDRE0);
UDR0 = c;
return 0;
}
// 从串口输入一个字符
static char uart_getchar(FILE *stream)
{
loop_until_bit_is_set(UCSR0A, RXC0);
return UDR0;
}
#include <stdio.h>
// 从串口输出一个字符
static int uart_putchar(char c, FILE *stream)
{
if (c == '\n')
uart_putchar('\r', stream);
loop_until_bit_is_set(UCSR0A, UDRE0);
UDR0 = c;
return 0;
}
// 从串口输入一个字符
static char uart_getchar(FILE *stream)
{
loop_until_bit_is_set(UCSR0A, RXC0);
return UDR0;
}
(2)定义IO
这一句是关键
FILE uartio = FDEV_SETUP_STREAM(uart_putchar, uart_getchar, _FDEV_SETUP_RW);
(3)设置波特率
// 波特率
#define BAUD 9600
#include <util/setbaud.h>
(4)初始化串口
stdout = &uartio;这一句比较重要
// 串口初始化
void UartInit()
{
cli();
/* 设置波特率 */
UBRR0H=UBRRH_VALUE;
UBRR0L=UBRRL_VALUE;
/* 接收器与发送器使能, 中断接收数据 */
UCSR0B = _BV(RXCIE0) | _BV(RXEN0) | _BV(TXEN0);
/* 设置帧格式: 8 个数据位, 1个停止位 */
UCSR0C = _BV(UCSZ01) | _BV(UCSZ00);
stdout = &uartio;
sei();
}
(5)串口输入输出
//输出:
printf("%d", 123);
//输入:
//输入时,程序会停在scanf,等待从串口输入数据
scanf("%c", &temp);
方法2:
2.自定义printf()
优点:占用ROM和RAM相对第一种方法少了很多
缺点:要自定义printf函数
(1)定义输出函数
// 输出一个字符
static void uart_putchar(char c)
{
loop_until_bit_is_set(UCSR0A, UDRE0);
UDR0 = c;
}
(2)设置波特率
同方法1
(3)初始化串口
同方法1
只是少了stdout = &uartio;这一句
(4)定义uart_printf()
// 从串口输出字符串,参数可变
void uart_printf(const char *fmt, ...)
{
const char *s;
int d;
char c;
char buf[6];
va_list ap;
// 使ap指向fmt参数的下一个参数
va_start(ap, fmt);
while (*fmt)
{
if (*fmt != '%')
{
uart_putchar(*fmt++);
continue;
}
switch (*++fmt)
{
// %s
case 's':
// 把参数按const char *型取出来,同时ap指向下一个参数
s = va_arg(ap, const char *);
for ( ; *s; s++)
{
uart_putchar(*s);
}
break;
// %d
case 'd':
d = va_arg(ap, int);
itoa(d, buf, 10);
for (s = buf; *s; s++)
{
uart_putchar(*s);
}
break;
// %c
case 'c':
// Default Argument Promotion
// 形参列表中有...,实参的char类型被提升为int型
c = (char)va_arg(ap, int);
uart_putchar(c);
break;
default:
uart_putchar(*fmt);
break;
}
fmt++;
}
va_end(ap);
}
当然也可以在uart_printf中使用更简洁的语句实现,如:
va_start(ap, fmt);
vsprintf(buf, fmt, ap);
va_end(ap);
uart_putstr(buf);
但这样占用的ROM和RAM空间同样会占用较多
(5)中断接收数据
// 串口接收中断服务程序
ISR(USART_RX_vect)
{
char val;
val = UDR0;
//数据处理
}