Launchpad 移植printf和scanf,以及对超级终端交互的优化
来源:互联网 发布:vc http post json 编辑:程序博客网 时间:2024/05/02 02:57
前言
printf,scanf只负责格式化输入输出的字符,他们分别依靠getchar和putchar函数,只要实现在单片机上的getchar函数和putchar函数,并且头文件包含stdio.h
即可正常使用printf函数和scanf函数。
第一步,配置UART及初始化模块
/**UART模块初始化函数*/void Uart_Init(void){ //-----开启IO口的TXD和RXD功能----- P1SEL = BIT1 + BIT2 ; // P1.1 = RXD, P1.2=TXD P1SEL2 = BIT1 + BIT2; UCA0CTL1 |= UCSWRST; //-----设置UART时钟源为ACLK----- UCA0CTL1 |= UCSSEL_2; // CLK = SMCLK //-----配置波特率参数9600bps----- UCA0BR0 = 0x41; UCA0BR1 = 0x03; UCA0MCTL = 0x00; //复位及开中断 UCA0CTL1 &= ~UCSWRST; // **Initialize USCI state machine** IE2 |= UCA0RXIE; // Enable USCI_A0 RX interrupt __bis_SR_register(GIE); }
第二步,编写基本收发函数
/**发送一个字符/数字 八位-一个字节*参数:__Char:字符*/void Send_Char(uint8 Char){ while(!(IFG2 & UCA0TXIFG));//SBUFF为空时触发标志位执行下面语句 UCA0TXBUF=Char; }/**发送一个字符串*参数:__Str:字符*/void Send_String(uchar *Str){ uchar i=0; while(Str[i]!='\0') { Send_Char(Str[i]); i++; } Send_Char(Str[i]);}/**接收一个字符*/uchar get_char(void){ __bis_SR_register(LPM0_bits); //进入低功耗等待接受中断发生 return Receive_Data; //返回接收中断返回的数据}
对于接收采用中断方式
//响应Rx中断服务#pragma vector=USCIAB0RX_VECTOR__interrupt void USCI0RX_ISR(void){ while (!(IFG2&UCA0TXIFG)); // USCI_A0 TX buffer ready? Receive_Data=UCA0RXBUF; IFG2 &= ~UCA0RXIFG; __bic_SR_register_on_exit(LPM0_bits);}
可以看到在接收中断中使单片机退出低功耗模式,为什么这么做?
当我们在使用scanf
函数的时候我们是不是要等待输入呢?这个等待的操作在上面的基本函数get_char
中实现:
/**接收一个字符*/uchar get_char(void){ __bis_SR_register(LPM0_bits); //进入低功耗等待接受中断发生 return Receive_Data; //返回接收中断返回的数据}
- 当程序中使用
scanf
函数会调用get_char
这时便会进入低功耗模式等待接收中断的发生。 - 若收到数据,中断发生,此时在中断中将接收到的数据传送给全局变量
Receive_Data
紧接着退出低功耗模式。 - 此时程序回到
get_char
处继续执行return Receive_Data;
便实现了返回接收字符的功能。
第三步,移植
对于putchar函数的重定向很简单
/**putchar 重定向*/int putchar(int ch){ if(ch=='\n') Send_Char('\r'); //回车前添加换行符 Send_Char(ch); return ch;}
而 getchar
正常基本功能来讲做到下面就可以了
int getchar(void){ return get_char();}
但是我们想要在超级终端上正常的进行交互,那输入的时候我们想要看到自己输入的字符怎么办?万一输入错一个字符想要删除怎么办?scanf函数本身并不支持删除操作,他只能顺序解析ASCII码字符串,所以为了实现退格操作需要开辟一个缓冲区,先处理键盘的输入与退格操作,等到输入完毕按回车键时,再将缓冲区的内容依次送回。
/**getchar 重定向*/int getchar(void) { static char io_buffer[LINE_LENGTH + 2]; //Where to put chars static char ptr; //Pointer in buffer char c; while (1) { if (io_buffer[ptr]) //如果缓冲区有字符 return (io_buffer[ptr++]); //则逐个返回字符 ptr = 0; //直到发送完毕,缓冲区指针归零 while (1) //缓冲区没有字符,则等待字符输入 { c = get_char(); //等待接收一个字符 if (c == In_EOF && !ptr) //==EOF== Ctrl+Z { //只有在未入其他字符时才有效 put_message(Out_EOF); //终端显示EOF符 return EOF; //返回 EOF(-1) } if (c == In_DELETE || c == In_BACKSP) //==退格或删除键== { if (ptr) //缓冲区有值 { ptr--; //从缓冲区移除一个字符 put_message(Out_DELETE); //同时显示也删掉一个字符 } } else if (c == In_SKIP) //==取消键 Ctrl+C == { put_message(Out_SKIP); //终端显示跳至下一行 ptr = LINE_LENGTH + 1; //==0 结束符== break; } else if (c == In_EOL) //== '\r' 回车== { putchar(io_buffer[ptr++] = '\n'); //终端换行 io_buffer[ptr] = 0; //末尾添加结束符(NULL) ptr = 0; //指针清空 break; } else if (ptr < LINE_LENGTH) //== 正常字符 == { if (c >=0x20) //删除 0x20以下字符 { //存入缓冲区 putchar(io_buffer[ptr++] = c); } } else //缓冲区已满 { putchar('\7'); //== 0x07 蜂鸣符,PC回响一声 } } }}
下面是常用特殊ASCII码的宏定义
//--------------------------------------------------------------------------------#define LINE_LENGTH 20 //行缓冲区大小,决定每行最多输入的字符数/*标准终端设备中,特殊ASCII码定义,请勿修改*/#define In_BACKSP 0x08 //ASCII <-- (退格键)#define In_DELETE 0x7F //ASCII <DEL> (DEL 键)#define In_EOL '\r' //ASCII <CR> (回车键)#define In_SKIP '\3' //ASCII control-C#define In_EOF '\x1A' //ASCII control-Z#define Out_DELETE "\x8 \x8" //VT100 backspace and clear#define Out_SKIP "^C\n" //^C and new line#define Out_EOF "^Z" //^Z and return EOF//---------------------------------------------------------------------------------
第四步,配置IAR环境
至此重定向工作基本算是完成了,只需要在工程中包含stdio.h即可。
当然IAR要做一些设置:
Project–>Options–>General Options–>Library Configuration.将Library设置为CLIB
第五步,配置超级终端
新建连接时,端口设置选项的数据流控制选“无”。
其它相关设置:
完成并测试
通过以下测试代码:
#include "includes.h"int a;void main( void ){ Sys_Init(); Uart_Init(); while(1) { printf("give a num!\n"); scanf("%d",&a); printf("the num is %d\n",a); }}
测试结果如下
以上。
1 0
- Launchpad 移植printf和scanf,以及对超级终端交互的优化
- MSP430 移植printf和scanf
- stm32CubeMx上移植自己的printf()和scanf()函数
- 基于S3C6410的ARM11 移植printf和scanf
- 【OK6410裸机程序】移植printf和scanf
- 移植自己写的printf,scanf函数
- scanf和printf的缓冲区
- printf 和 scanf 的使用
- 关于printf()和scanf()的返回值以及printf的嵌套
- win7下的超级终端的移植
- [smart210] 裸板移植printf()与scanf()的步骤
- scanf 和 printf的一般用法
- 测试printf 和scanf函数的用法
- Printf 和 scanf 的用法 ( 简单入门)
- printf ,scanf 的应用和区别
- scanf(),printf()和gets(),puts()的区别
- printf和scanf函数的返回值
- 关于scanf函数和printf的总结
- Xcode请求不了数据看这里
- Installing Virtual Machines with virt-install
- 支付宝集成过程详解——运行DEMO
- sass的安装(mac OSX、window OS)
- Maven的入门
- Launchpad 移植printf和scanf,以及对超级终端交互的优化
- ffmpeg使用
- 自定义Dialog产生局部背景问题
- 基于Eclipse Maven的Spring4/Spring-MVC/Hibernate4整合之六:Hibernate的flush和clear
- HTTP详解
- 【UI】【View】View事件分发(一)
- 6. ZigZag Conversion
- ubuntu 14.04 安装adobe flash
- 日志分析hive