第四章 使用C 语言标准I/O 流调试程序
4.1 avr-libc标准I/O流描述
avr-libc 提供标准I/O流stdin, stdout和stderr。但受硬件资源的限制仅支持标准C语言I/O流的部分功能。由于没有操作系统支持,avr-libc又不知道标准流使用的设备,在应用程序的startup过程中I/O流无法初始化。同样在avr-libc中没有文件的概念,它也不支持fopen()。做为替代 fdevopen()提供流与设备间的连接。fdevopen需要提供字符发送、字符接收两个函数,在avr-libc中这两个函数对于字符流与二进制流是没有区别的。
三个核心函数
fdevopen()
应用程序通过fdevopen函数为流指定实际的输入输出设备。
FILE* fdevopen( int(* put) (char), int(* get)(void), int opts __attribute__((unused))
前两个参数均为指向函数的指针,它们指向的函数分别负责向设备输出一字节和从设备输入一字节的函数。第三个参数保留,通常指定0。
如果只指定put指针,流按写方式打开,stdout 或 stderr成为流的引用名。
如果只指定get指针,流按只读方式打开,stdin成为流的引用名。
如果在调用时两者都提供则按读写方式打开,此时stdout、stderr和stdin相同,均可做为当前流的引用名。
(1)向设备写字符函数:
原型:
int put(char c)
{
? ?
return 0;
}
返回0表示字符传送成功,返回非零表示失败。
另外,字符'\n'被I/O流函数传送时直接传送一个换行字符,因此如果设备在换行前需要回车,应当在put函数里发送 '\n'前发字符'\r'。
以下是一个基于UART的 put 示例:
int uart_putchar(char c)
{
if(c=='\n')
uart_putchar('\r');
loop_until_bit_is_set(UCSRA,UDRE);
UDR=c;
return 0;
}
(2)从设备输入字符函数
原型:
int get(void)
{
? ?
}
get 函数从设备读取一字节并按 int 类型返回,如果读取时发生了错误需返回 –1。
vfprintf()
int vfprintf ( FILE * __stream, const char * __fmt, va_list __ap )
vfprintf 将__ap列出的值按__fmt 格式输出到流__stream。返回输出字节数,若产生错误返回EOF。
vfprintf是libc提供的I/O流格式化输出函数的基础,为避免应用中用不到的功能占用宝贵的硬件资源,vfprintf函数支持三种不同链接模式。
(1) 在默认情况下它包含除浮点数格式转换外的所有功能
(2) 最小模式仅包含基本整数类型和字符串转换功能要用最小模式链接此函数,使用的链接选项如下:
-Wl,-u,vfprintf -lprintf_min
(3) 完全模式支持浮点数格式转换在内的所有功能。
完全模式链接选项如下:
-Wl,-u,vfprintf -lprintf_flt –lm
vfscanf()
int vfscanf ( FILE * __stream, const char * __fmt, va_list __ap )
vfscanf 是libc 提供的I/O 流格式化输入函数的基础, 它从__stream 流按字符格式读取__fmt 内容后按转换规则将数据保存到__ap 内。与vfprintf 类似vfscanf 也支持三种不同链接模式。
(1)在默认情况下它支持除浮点数格式和格式“%[”外的所有转换。
(2)最小模式链接选项:
-Wl,-u,vfscanf -lscanf_min -lm
(3)完全模式链接选项:
-Wl,-u,vfscanf -lscanf_flt –lm
4.2 利用标准I/0流调试程序
在程序的调试阶段,提供数据格式化输入/输出功能的标准I/O函数是个非常有用的工具,而单片机UART接口是标准I/O的比较合适设备
一. 电路

图4-1 UART 实现I/O 流电路原理图
二.程序
/*
avr-libc 标准 i/o 测试程序
main.c
mcu:atmega8
芯艺 2004-09-09
*/
#include
#include
#include
char g_aString[81];
//uart 发送一字节
int usart_putchar(char c)
{
if(c=='\n')
usart_putchar('\r');
loop_until_bit_is_set(UCSRA,UDRE);
UDR=c;
return 0;
}
//uart 接收一字节
int usart_getchar(void)
{
loop_until_bit_is_set(UCSRA,RXC);
return UDR;
}
void IoInit(void)
{
//uart 初始化
UCSRB=_BV(RXEN)|_BV(TXEN);/*(1<UBRRL=25; //9600 baud 6MHz:38 4MHz:25
//流与设备连接
fdevopen(usart_putchar,usart_getchar,0);
}
int main(void)
{
int tmp;
IoInit();
while(1)
{
//测试1
vfprintf(stdout,"测试1[输入数字]:\n",0);
vfscanf(stdin,"%d",&tmp);
vfprintf(stdout,"您的输入为:%d\n",tmp);
//测试2
printf("测试2[输入一字符串]:\n");
scanf("%s",g_aString);
printf("您的输入为:%s\n",g_aString);
//测试3
printf_P(PSTR("测试3[输入数字]:\n"));
scanf_P(PSTR("%d"),&tmp);
printf_P(PSTR("您的输入为:%d\n"),tmp);
}
}
三.监测工具

图4-2 PrintMonitor 运行界面
监测工具PrintMonitor 运行界面如图4-2 所示,它属于windows 应用程序,由VisualBasic6.0 编写,请到http://bitfu.zj.com 下载源代码。
单片机教程,五系列(55讲)电子书全集下载论坛精选:
单片机教程,MCS51单片机从零开始 第一讲:初识单片机
http://bbs.huazhoucn.com/Topic.aspx?id=2539
单片机教程,MCS51单片机从零开始 第二讲:MCS-51单片机简述
http://bbs.huazhoucn.com/Topic.aspx?id=2540
单片机教程,MCS51单片机从零开始 第三讲:单片机相关常用名词解释
http://bbs.huazhoucn.com/Topic.aspx?id=2541
单片机教程,MCS51单片机从零开始 第四讲:计算机中数的表示及运算
http://bbs.huazhoucn.com/Topic.aspx?id=2542
单片机教程,MCS51单片机从零开始 第五讲:常用逻辑电路
http://bbs.huazhoucn.com/Topic.aspx?id=2544
单片机教程,MCS51单片机从零开始 第六讲:51单片机的结构及其组成
http://bbs.huazhoucn.com/Topic.aspx?id=2545
单片机教程,MCS51单片机从零开始 第七讲:51单片机的引脚
http://bbs.huazhoucn.com/Topic.aspx?id=2546
单片机教程,MCS51单片机从零开始 第八讲:8051单片机I/O引脚工作原理
http://bbs.huazhoucn.com/Topic.aspx?id=2547
单片机教程,MCS51单片机从零开始 第九讲:8051单片机的存储器结构
http://bbs.huazhoucn.com/Topic.aspx?id=2548
单片机教程,MCS51单片机从零开始 第十讲:编码及译码器工作原理
http://bbs.huazhoucn.com/Topic.aspx?id=2549
单片机教程,MCS51单片机从零开始 第十一讲:存储器的存储原理
http://bbs.huazhoucn.com/Topic.aspx?id=2550
单片机教程,MCS51单片机从零开始 第十二讲:51单片机的特殊功能寄存器
http://bbs.huazhoucn.com/Topic.aspx?id=2551
单片机教程,MCS51单片机从零开始 第十三讲:51单片机CPU的内部结构
http://bbs.huazhoucn.com/Topic.aspx?id=2552
单片机教程,MCS51单片机从零开始 第十四讲:定时器/计数器的基本结构及工作原理
http://bbs.huazhoucn.com/Topic.aspx?id=2553
单片机教程,MCS51单片机从零开始 第十五讲:51单片机的中断系统
http://bbs.huazhoucn.com/Topic.aspx?id=2554
单片机教程,MCS51单片机从零开始 第十六讲:51单片机的复位
http://bbs.huazhoucn.com/Topic.aspx?id=2555
单片机教程,MCS51单片机从零开始 第十七讲:51单片机执行指令的过程
http://bbs.huazhoucn.com/Topic.aspx?id=2556
单片机教程,MCS51单片机从零开始 第十八讲:51单片机的延时及时序分析
http://bbs.huazhoucn.com/Topic.aspx?id=2557
单片机教程,MCS51单片机从零开始 第十九讲:汇编语言基础
http://bbs.huazhoucn.com/Topic.aspx?id=2558
单片机教程,MCS51单片机从零开始 第二十讲:汇编语言及汇编过程
http://bbs.huazhoucn.com/Topic.aspx?id=2556
单片机教程,MCS51单片机从零开始 第二十一讲:汇编程序的基本结构
http://bbs.huazhoucn.com/Topic.aspx?id=2560
单片机教程,MCS51单片机从零开始 第二十二讲:51单片机的寻址方式
http://bbs.huazhoucn.com/Topic.aspx?id=2561
单片机教程,MCS51单片机从零开始 第二十三讲:数据传送类指令分析
http://bbs.huazhoucn.com/Topic.aspx?id=2562
单片机教程,MCS51单片机从零开始 第二十四讲:算术运算类指令分析
http://bbs.huazhoucn.com/Topic.aspx?id=2563
单片机教程,MCS51单片机从零开始 第二十五讲:逻辑运算及移位指令分析
http://bbs.huazhoucn.com/Topic.aspx?id=2564
单片机教程,MCS51单片机从零开始 第二十六讲:控制转移类指令分析
http://bbs.huazhoucn.com/Topic.aspx?id=2565
单片机教程,MCS51单片机从零开始 第二十七讲:布尔变量操作指令分析
http://bbs.huazhoucn.com/Topic.aspx?id=2566
单片机教程,MCS51单片机从零开始 第二十八讲:伪指令分析
http://bbs.huazhoucn.com/Topic.aspx?id=2567