MSP430 移植printf和scanf
硬件介紹:
硬件部分只需字符型輸入輸出設(shè)備:scanf從輸入字符型設(shè)備讀取字符,printf輸出到字符型輸出設(shè)備。在這里,我選用的字符型輸入設(shè)備是超級終端,通過串口與單片機(jī)連接,輸入字符;輸出設(shè)備是超級終端和12864的液晶。scanf從串口讀入字符,printf輸出字符到串口和液晶。
有關(guān)串口的預(yù)提信息參考:MSP430程序庫<二>UART異步串口。
有關(guān)液晶的具體信息參考:MSP430程序庫<三>12864液晶程序庫。
scanf還可以從按鍵讀取信息,可以參考移置方法自行移置。
程序?qū)崿F(xiàn):
printf
單片機(jī)在調(diào)用printf時(shí),printf是負(fù)責(zé)將數(shù)據(jù)解析成ASCII碼流,通過調(diào)用putchar函數(shù)依次將字符發(fā)出。如果在putchar內(nèi)編寫從串口發(fā)送一字節(jié)數(shù)據(jù),則printf的結(jié)果將從單片機(jī)串口發(fā)送出;如果putchar是向液晶寫字符,讓液晶顯示一個(gè)字符,則printf的結(jié)果將顯示在液晶上。本程序?qū)崿F(xiàn)putchar同時(shí)向串口和液晶同時(shí)發(fā)送一個(gè)字符(液晶是顯示一個(gè)字符)。
putchar函數(shù)如下:
int putchar(int ch)
{
putchar2Com(ch);
putchar2Lcd(ch);
return (ch);
}
程序先向串口發(fā)送一個(gè)字符,然后像向晶發(fā)送字符。
其中:putchar2Com,向串口發(fā)送一個(gè)字符,代碼如下:
int putchar2Com(int ch)
{
if (ch == 'n') // 'n'(回車)擴(kuò)展成 'n''r' (回車+換行)
{
UartWriteChar('r') ; //0x0d 換行
}
UartWriteChar(ch); //從串口發(fā)出數(shù)據(jù)
return (ch);
}
代碼僅僅調(diào)用向串口寫字符的函數(shù)UartWriteChar(ch)(詳見Uart.c,在<二>中有介紹),當(dāng)要輸出換行時(shí),需先輸出’n’將光標(biāo)移至本行首位置,還需要’r’(換行)才能將光標(biāo)置于下一行起始位置,即將’n’擴(kuò)展為’r’,’n’兩個(gè)字節(jié)依次發(fā)出。
purchar2Lcd函數(shù)比較復(fù)雜,因?yàn)槲宜褂玫?2864液晶是中文字庫的液晶,每行8個(gè)地址,可以顯示8個(gè)中文字符或16個(gè)英文字符,而putchar只發(fā)出一個(gè)字節(jié),需要判斷每個(gè)地址的前半字還是后半字(因?yàn)槊總€(gè)字可以顯示中文,如果中文的兩個(gè)字節(jié)在相鄰的兩個(gè)地址上,將不會(huì)顯示,或是顯示亂碼)。
上代碼:
int putchar2Lcd(int ch)
{
char addr,dat;
if (ch == 'n') // 'n'(回車),換行
{
ChangeNextRow();
}
else
{
addr = LcdReadAddr();
if(ch < 0x80)
{
LcdWriteData(ch);
}
else
{
LcdWriteData(0x20); //寫入一個(gè)空字符,根據(jù)地址判斷是否為前半字
if(addr == LcdReadAddr()) //前半字 從新寫入ch字符
{
LcdWriteComm(addr);
LcdWriteData(ch);
}
else
{
LcdWriteComm(addr);
dat = LcdReadData();
if(dat < 0x80) //前一個(gè)字符是英文字符
{
LcdWriteData(0x20); //空格
}
LcdWriteData(ch);
}
}
}
if((addr != LcdReadAddr()) && //寫入的是行最后位的后半字則換行
(addr==0x87 || addr==0x97 || addr==0x8F || addr==0x9F))
{
ChangeNextRow();
}
return (ch);
}
這個(gè)函數(shù)首先判斷換行;然后處理其他一般字符,如果是英文字符,不用考慮前后半字,只需正常寫入液晶即可;如果是中文字符,在判斷是否是前半字,前半字則直接寫入,后半字則判斷之前寫入的前半字是否是中文,是則直接寫入,不是則把英文字符移入后半字,然后寫入;最后判斷是否到行尾,是則換行。
程序更新為:更新日期:20110821 18:51
目的是修復(fù)原來,行尾前半字為英文,再輸入中文會(huì)顯示亂碼。
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); //寫入一個(gè)空字符,根據(jù)地址判斷是否為前半字
if(addr == LcdReadAddr()) //前半字 從新寫入ch字符
{
LcdWriteComm(addr);
LcdWriteData(ch);
}
else
{
LcdWriteComm(addr);
dat = LcdReadData();
if(dat < 0x80) //前一個(gè)字符是英文字符
{
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);
}
前后半字判斷方法如下:讀液晶地址,向液晶寫入一個(gè)空格,再讀地址,兩地址相同則是前半字,不同則是后半字。讀地址函數(shù)在Lcd12864.c中,新加入函數(shù),代碼如下:
char LcdReadAddr()
{
char ch;
WaitForEnable();
CLR_RS;
SET_RW;
DATA_DIR_IN;
SET_EN;
_NOP();
ch = DATA_IN; //讀數(shù)據(jù)
CLR_EN;
DATA_DIR_OUT;
return (ch|0x80);
}
這個(gè)是讀地址,ch|0x80是因?yàn)閷懭胍壕У刂肥孜粦?yīng)為1.。
液晶中新加入兩個(gè)函數(shù),一個(gè)是上邊的讀地址,另外一個(gè)是讀數(shù)據(jù);作用是讀取液晶當(dāng)前地址處的數(shù)據(jù),從而判斷之前半字是否是中文。代碼如下:
char LcdReadData()
{
char ch;
WaitForEnable();
SET_RS;
SET_RW;
DATA_DIR_IN;
SET_EN;
_NOP();
ch = DATA_IN; //讀數(shù)據(jù)
CLR_EN;
DATA_DIR_OUT;
return ch;
}
另外 putchar還調(diào)用了換行——ChangeNextRow函數(shù),完成液晶輸出換至下一行。
代碼如下:
void ChangeNextRow()
{
char addr;
addr = LcdReadAddr(); //當(dāng)前地址
if(addr <= 0x88)
{
LcdWriteComm(0x90);
}
else if(addr <= 0x90)
{