printf 和scanf函数是C语言中最常用的输入出函数,从学习C语言开始,就开始使用这两个函数,然而当写用C语言写单片机程序时却不能使用这两个函数,总觉得单片机的C语言和一般的C语言差别很大,写起来不大方便;其实,单片机的C语言也是标准C语言上扩展或是改动的,都支持格式化输入输出函数(printf 和scanf);事实上,printf,scanf只负责格式化输入输出的字符,至于从哪儿输入,输出到哪儿,他们分别依靠getchar和putchar函数,只要实现单片机上的getchar函数和putchar函数,即可正常使用printf函数和scanf函数,这可以给我们单片机的信息交互带来很多方便。下面我们就来实现他们的移置。
硬件介绍:
硬件部分只需字符型输入输出设备:scanf从输入字符型设备读取字符,printf输出到字符型输出设备。在这里,我选用的字符型输入设备是超级终端,通过串口与单片机连接,输入字符;输出设备是超级终端和12864的液晶。scanf从串口读入字符,printf输出字符到串口和液晶。
有关串口的预提信息参考:MSP430程序库<二>UART异步串口。
有关液晶的具体信息参考:MSP430程序库<三>12864液晶程序库。
scanf还可以从按键读取信息,可以参考移置方法自行移置。
程序实现:
printf
单片机在调用printf时,printf是负责将数据解析成ASCII码流,通过调用putchar函数依次将字符发出。如果在putchar内编写从串口发送一字节数据,则printf的结果将从单片机串口发送出;如果putchar是向液晶写字符,让液晶显示一个字符,则printf的结果将显示在液晶上。本程序实现putchar同时向串口和液晶同时发送一个字符(液晶是显示一个字符)。
putchar函数如下:
int putchar(int ch)
{
putchar2Com(ch);
putchar2Lcd(ch);
return (ch);
}
程序先向串口发送一个字符,然后像向晶发送字符。
其中:putchar2Com,向串口发送一个字符,代码如下:
int putchar2Com(int ch)
{
if (ch == 'n') // 'n'(回车)扩展成 'n''r' (回车+换行)
{
UartWriteChar('r') ; //0x0d 换行
}
UartWriteChar(ch); //从串口发出数据
return (ch);
}
代码仅仅调用向串口写字符的函数UartWriteChar(ch)(详见Uart.c,在<二>中有介绍),当要输出换行时,需先输出’n’将光标移至本行首位置,还需要’r’(换行)才能将光标置于下一行起始位置,即将’n’扩展为’r’,’n’两个字节依次发出。
purchar2Lcd函数比较复杂,因为我所使用的12864液晶是中文字库的液晶,每行8个地址,可以显示8个中文字符或16个英文字符,而putchar只发出一个字节,需要判断每个地址的前半字还是后半字(因为每个字可以显示中文,如果中文的两个字节在相邻的两个地址上,将不会显示,或是显示乱码)。
上代码:
int putchar2Lcd(int ch)
{
char addr,dat;
if (ch == 'n') // 'n'(回车),换行
{
ChangeNextRow();
}
else
{
addr = LcdReadAddr();
if(ch < 0x80)
{
LcdWriteData(ch);
}
else
{
LcdWriteData(0x20); //写入一个空字符,根据地址判断是否为前半字
if(addr == LcdReadAddr()) //前半字 从新写入ch字符
{
LcdWriteComm(addr);
LcdWriteData(ch);
}
else
{
LcdWriteComm(addr);
dat = LcdReadData();
if(dat < 0x80) //前一个字符是英文字符
{
LcdWriteData(0x20); //空格
}
LcdWriteData(ch);
}
}
}
if((addr != LcdReadAddr()) && //写入的是行最后位的后半字则换行
(addr==0x87 || addr==0x97 || addr==0x8F || addr==0x9F))
{
ChangeNextRow();
}
return (ch);
}
这个函数首先判断换行;然后处理其他一般字符,如果是英文字符,不用考虑前后半字,只需正常写入液晶即可;如果是中文字符,在判断是否是前半字,前半字则直接写入,后半字则判断之前写入的前半字是否是中文,是则直接写入,不是则把英文字符移入后半字,然后写入;最后判断是否到行尾,是则换行。
程序更新为:更新日期:20110821 18:51
目的是修复原来,行尾前半字为英文,再输入中文会显示乱码。
int putchar2Lcd(int ch)
{
char addr,dat;
char changeRowFlag = 0;
if (ch == 'n') // 'n'(回车),换行
{
ChangeNextRow();
changeRowFlag = 1;
}
else if (ch == 'b') // 'b' (退格)
{
BackSpace();
}
else
{
addr = LcdReadAddr();
if(ch < 0x80)
{
LcdWriteData(ch);
}
else
{
LcdWriteData(0x20); //写入一个空字符,根据地址判断是否为前半字
if(addr == LcdReadAddr()) //前半字 从新写入ch字符
{
LcdWriteComm(addr);
LcdWriteData(ch);
}
else
{
LcdWriteComm(addr);
dat = LcdReadData();
if(dat < 0x80) //前一个字符是英文字符
{
LcdWriteData(0x20); //空格
}
if((addr != LcdReadAddr()) && //写入的是行最后位的后半字则换行
(addr==0x87 || addr==0x97 || addr==0x8F || addr==0x9F))
{
ChangeNextRow();
changeRowFlag = 1;
}
LcdWriteData(ch);
}
}
}
if((addr != LcdReadAddr()) && //写入的是行最后位的后半字则换行,且未换过行
(changeRowFlag == 0) &&
(addr==0x87 || addr==0x97 || addr==0x8F || addr==0x9F))
{
ChangeNextRow();
}
return (ch);
}
前后半字判断方法如下:读液晶地址,向液晶写入一个空格,再读地址,两地址相同则是前半字,不同则是后半字。读地址函数在Lcd12864.c中,新加入函数,代码如下:
char LcdReadAddr()
{
char ch;
WaitForEnable();
CLR_RS;
SET_RW;
DATA_DIR_IN;
SET_EN;
_NOP();
ch = DATA_IN; //读数据
CLR_EN;
DATA_DIR_OUT;
return (ch|0x80);
}
这个是读地址,ch|0x80是因为写入液晶地址首位应为1.。
液晶中新加入两个函数,一个是上边的读地址,另外一个是读数据;作用是读取液晶当前地址处的数据,从而判断之前半字是否是中文。代码如下:
char LcdReadData()
{
char ch;
WaitForEnable();
SET_RS;
SET_RW;
DATA_DIR_IN;
SET_EN;
_NOP();
ch = DATA_IN; //读数据
CLR_EN;
DATA_DIR_OUT;
return ch;
}
另外 putchar还调用了换行——ChangeNextRow函数,完成液晶输出换至下一行。
代码如下:
void ChangeNextRow()
{
char addr;
addr = LcdReadAddr(); //当前地址
if(addr <= 0x88)
{
LcdWriteComm(0x90);
}
else if(addr <= 0x90)
{
LcdWriteComm(0x98);
}
else if(addr <= 0x98)
{
LcdWriteComm(0x88);
}
else
{
AddNewline(); //添加行,同时向上滚动
LcdWriteComm(0x98);
}
}
读取当前地址,判断在哪一行,然后写入下一行首地址;如果是最后一行,则所有安徽那个向上移,写入最后一行首地址。
AddNewLine函数完成所有行向上滚动一行,然后地址定位至最后一行。
代码如下:
void AddNewline()
{
char str[17];
str[16] = 0;
//第二行 移至第一行
LcdWriteComm(0x90);
LcdReadData(); //空读取
for(int i = 0;i<16;i++)
{
str[i] = LcdReadData();
}
LcdWriteString(0x80,str);
//第三行 移至第二行
LcdWriteComm(0x88);
LcdReadData();
for(int i = 0;i<16;i++)
{
str[i] = LcdReadData();
}
LcdWriteString(0x90,str);
//第四行 移至第三行
LcdWriteComm(0x98);
LcdReadData();
for(int i = 0;i<16;i++)
{
str[i] = LcdReadData();
}
LcdWriteString(0x88,str);
//第四行 空白
LcdWriteString(0x98," "); //十六个空格
}
读出下一行数据,写入上一行,最后一行写入空格即可。
到此putchar函数全部完成,printf移植的程序部分完成,使用方法详见使用示例。
scanf
scanf和printf类似,其只负责格式化输入的字符,字符来源是从getchar函数获取;同样,在使用scanf函数之前,要针对字符输入源自行编写getchar函数
最简getchar:
int getchar()
{
return (putchar(UartReadChar()));
}
这是最简单的getchar函数,直接调用读取字符函数,输出并返回。
但是人的输入过程会偶尔犯错误的,为了支持退格键等,需要开辟一个缓存区。
详细代码如下:
#define LINE_LENGTH 80 //行缓冲区大小,决定每行最多输入的字符数
上一篇:基于MSP430F413水果电池供电的低功耗时钟
下一篇:MSP430程序库<三>12864液晶程序库
推荐阅读
史海拾趣
随着全球环保意识的日益增强,电子行业也开始面临着越来越严格的环保要求。Ferroxcube公司作为行业领军企业,积极响应环保号召,开始研发更加环保的磁性元件。
经过长时间的研发和试验,公司成功推出了一款采用环保材料制成的新型磁芯。这款磁芯不仅性能优异,而且在使用寿命结束后可以方便地进行回收再利用,大大降低了对环境的污染。
这一创新产品一经推出,就受到了市场的热烈欢迎。许多环保意识强烈的客户纷纷选择使用Ferroxcube的环保磁芯,以支持绿色环保事业。这也使得Ferroxcube在环保领域的声誉大大提升,为公司赢得了更多的市场份额和客户认可。
- 创业初期:
- 描述Clulite公司的创始人或核心团队如何识别电子行业中的某个市场机遇。
- 讲述他们是如何筹集初始资金,设立公司,并开发出第一款产品或解决方案的。
- 可以提及公司在初创阶段面临的挑战,如技术难题、市场竞争等。
- 技术创新:
- 讲述Clulite如何通过研发创新,推出了一款颠覆性的产品或技术,从而获得了市场认可。
- 详细描述这一创新过程,包括研发团队的努力、关键技术的突破等。
- 提及这一创新如何帮助公司在市场上取得了竞争优势。
- 市场拓展:
- 描述Clulite如何逐步扩大市场份额,从地区市场走向全国乃至国际市场。
- 可以讲述公司如何建立销售网络、与合作伙伴建立合作关系,以及参与行业展会等活动来推广品牌和产品。
- 提及公司在市场拓展过程中遇到的挑战和应对策略。
- 品质管理:
- 讲述Clulite如何注重产品质量和客户体验,通过严格的质量控制流程来提升产品可靠性。
- 描述公司如何建立完善的售后服务体系,为客户提供及时、专业的支持。
- 提及这些举措如何帮助公司赢得了客户的信任和口碑。
- 可持续发展:
- 讲述Clulite如何关注环境保护和社会责任,推动公司的可持续发展。
- 描述公司如何采取环保措施,减少生产过程中的污染排放。
- 提及公司如何参与社会公益事业,回馈社会。
请注意,这些故事需要根据Clulite公司的实际情况进行调整和补充。如果你需要更具体的内容,建议查阅Clulite公司的官方网站、新闻报道或行业分析报告,以获取更详细的信息和数据。
在稳固了车规级IGBT芯片和模组代工市场地位的基础上,芯联集成开始积极拓展新的市场领域。公司凭借其在半导体制造领域的丰富经验和技术优势,成功进军碳化硅芯片和模块市场,并为多家头部新能源车企提供代工服务。此外,公司还计划向AI领域延伸,加强在AI领域的技术布局和市场拓展。这一举措将进一步拓宽芯联集成的业务范围,实现多元化发展。
EA Elektro-Automatik深知持续创新是企业发展的重要动力。因此,公司始终将创新作为企业文化的核心价值观之一。公司鼓励员工积极提出创新想法和解决方案,并为他们提供充分的支持和资源。此外,EA Elektro-Automatik还积极参与各类科研项目和行业标准的制定工作,推动整个行业的创新和发展。这种企业文化不仅为公司带来了更多的机会和挑战,也为企业的长期发展奠定了坚实的基础。
以上是关于EA Elektro-Automatik公司在电子行业发展的5个相关故事。这些故事展示了公司从创立到成为全球知名电子测量品牌的发展历程和取得的成就。
贝特莱与小米的合作是其发展历程中的又一重要事件。作为小米全系列合作伙伴,贝特莱为米家智能门锁提供了独家指纹传感器和定制算法芯片。随着米家智能门锁销量突破百万大关,贝特莱也实现了销售上的重大突破。这一合作不仅证明了贝特莱技术的成熟与可靠,也进一步提升了其在智能门锁市场的地位。
贝特莱与小米的合作是其发展历程中的又一重要事件。作为小米全系列合作伙伴,贝特莱为米家智能门锁提供了独家指纹传感器和定制算法芯片。随着米家智能门锁销量突破百万大关,贝特莱也实现了销售上的重大突破。这一合作不仅证明了贝特莱技术的成熟与可靠,也进一步提升了其在智能门锁市场的地位。
本帖最后由 paulhyde 于 2014-9-15 08:56 编辑 1.2.2 Wireless The WiFi settings are configured in the file /etc/config/wireless (currently supported on Broadcom, Atheros and mac80211). When booting the router for the first time it s ...… 查看全部问答∨ |
|
6410+wince6.0,我用的是华恒的bsp,发现otg驱动中,只有作为device的驱动,而没有作为host的驱动,请教各位的otg驱动也是如此嘛? 参照6410的spec,发现otg phy可以通过配置寄存器给usb host用,这点我已经实现,otg的口可以正常用于u盘,usb鼠标 ...… 查看全部问答∨ |
|
今天,看了一下电源管理,下午就动起手来,后来启动后无论怎么搞,都会不断的调用OEMIDLE函数,我在里面加的打印信息,不停的打印。 我就做了下面的修改而已 首先修改bootloader ;Check if the boot is caused by the wake-up from SLEEP mode. ...… 查看全部问答∨ |
DLL入口DLLMain两次被系统用DLL_PROCESS_DETACH调用 CE5下.自己写了个motola手机的USB驱动程序. 现在加载OK. 串口出来的信息如下: USBInstallDriver++ load USBD.DLL sucess! USBInstallDriver-- DLL_PROCESS_DETACH Device Attached! Looking for Stream Interfaces 2 2 There are 2 i ...… 查看全部问答∨ |