鍍金池/ 教程/ 數(shù)據(jù)庫/ 12.5 ?C 語言字符數(shù)組和字符指針
8.3 C 語言函數(shù)的形參和實(shí)參
12.2 C 語言指針變量的聲明
12.5 ?C 語言字符數(shù)組和字符指針
7.3 單片機(jī) LED 點(diǎn)陣的介紹
11.5 UART 串口通信的基本應(yīng)用
9.9 單片機(jī)蜂鳴器控制程序和驅(qū)動電路
10. 單片機(jī)實(shí)例練習(xí)與經(jīng)驗積累
10.3 單片機(jī)交通燈控制程序和設(shè)計原理
9.8 實(shí)用的 28BYJ-48 步進(jìn)電機(jī)控制程序
8.2 C 語言函數(shù)的調(diào)用
12.4 C 語言指向數(shù)組元素的指針
7.1 C 語言變量的作用域
11.2 RS232 通信接口
12.7 1602 液晶的讀寫時序介紹
7.2 C 語言變量的存儲類別
8. C 語言函數(shù)進(jìn)階與單片機(jī)按鍵
10.4 51單片機(jī) RAM 區(qū)域的劃分
12.1 C 語言變量的地址
11. UART 串口通信
7. 變量進(jìn)階與點(diǎn)陣 LED
8.4 單片機(jī)按鍵介紹
9.3 電機(jī)的分類
9.1 單片機(jī) IO 口的結(jié)構(gòu)
單片機(jī)通信實(shí)例與 ASCII 碼
8.1 單片機(jī)最小系統(tǒng)解析(電源、晶振和復(fù)位電路)
9.2 單片機(jī)上下拉電阻
11.4 單片機(jī) IO 口模擬 UART 串口通信
9.5 讓 28BYJ-48 步進(jìn)電機(jī)轉(zhuǎn)起來
9.7 28BYJ-48 步進(jìn)電機(jī)控制程序基礎(chǔ)
12.8 1602 液晶指令介紹
12.3 C 語言指針的簡單示例
8.7 單片機(jī)矩陣按鍵的掃描
7.4 單片機(jī) LED 點(diǎn)陣的圖形顯示
8.6 單片機(jī)按鍵消抖程序
10.2 單片機(jī)中 PWM 的原理與控制程序
7.6 單片機(jī) LED 點(diǎn)陣的橫向移動(動態(tài)顯示)
11.3 USB 轉(zhuǎn)串口通信
12.9 1602 液晶簡單顯示程序
9.4 28BYJ-48 步進(jìn)電機(jī)原理
8.5 ?單片機(jī)獨(dú)立按鍵掃描程序
12. C 語言指針基礎(chǔ)與1602液晶的初步認(rèn)識
9. 單片機(jī)中的步進(jìn)電機(jī)與蜂鳴器
10.1 單片機(jī)數(shù)字秒表程序
7.5 單片機(jī) LED 點(diǎn)陣的縱向移動(動態(tài)顯示)
8.8 單片機(jī)簡易加法計算器程序
11.1 單片機(jī)串行通信介紹
10.5 單片機(jī)長短按鍵的應(yīng)用
12.6 1602 液晶介紹(電路和引腳圖)
9.6 28BYJ-48 步進(jìn)電機(jī)轉(zhuǎn)動精度與深入分析

12.5 ?C 語言字符數(shù)組和字符指針

常量和符號常量

在程序運(yùn)行過程中,其值不能被改變的量稱之為常量。常量分為不同的類型,有整型常量如1、2、3、100;浮點(diǎn)型常量3.14、0.56、-4.8;字符型常量?a?、?b?、?0?;字符串常量“a”、“abc”、“1234”、“1234abcd”等。

細(xì)心的同學(xué)會發(fā)現(xiàn),整型和浮點(diǎn)型常量我們直接寫的數(shù)字,而字符型常量用單引號來表示一個字符,用雙引號來表示一個字符串,尤其大家要注意?a?和“a”是不一樣的,這個等會我們要詳細(xì)介紹。

常量一般有兩種表現(xiàn)形式:

  • 直接常量:直接以值的形式表示的常量稱之為直接常量。上述舉例這些都是直接常量,直接寫出來了。
  • 符號常量:用標(biāo)識符命名的常量稱之為符號常量,就是為上面的直接常量再取一個名字。使用符號常量一是方便理解,提高程序可讀性,更重要的是方便程序的后續(xù)維護(hù),習(xí)慣上符號常量我們都用大寫字母和下劃線來命名。

比如,我們可以把3.14取名為 PI(即π)。再比如,我們上節(jié)課的串口程序,我們用的波特率是9600,如果用符號常量來進(jìn)行提前聲明的話,那我們要修改成其它速率的話,就不用在程序中找9600修改了,直接修改聲明處就可以了,兩種方法舉例說明。用 const 聲明。比如我們在程序開始位置定義一個符號常量 BAUD。

定義形式是:

    const  類型  符號常量名字=常量值;

    const unsigned int BAUD = 9600;  /*注意結(jié)尾有個分號*/

我們就可以在程序中直接把9600改成 BAUD,這樣我們?nèi)绻牟ㄌ芈实脑?,直接在程序開頭位置改一下這個值就可以了。用預(yù)處理命令 #define 來完成,預(yù)處理命令我們先來認(rèn)識 #define。

定義形式是:

    #define  符號常量名  常量值

    #define  BAUD  9600  /*注意結(jié)尾沒有分號*/

這樣定義以后,只要在程序中出現(xiàn) BAUD 的話,意思就是完全替代了后邊的9600這個數(shù)字。

不知大家是否記得,我們之前定義數(shù)碼管真值表的時候,用了一個 code 關(guān)鍵字。

unsigned char code LedChar[] = {  //數(shù)碼管顯示字符轉(zhuǎn)換表
    0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,
    0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
};

我們當(dāng)時說加了 code 之后,這個真值表的數(shù)據(jù)只能被使用,不能被改變,如果我們直接寫 LedChar[0] = 1;這樣就錯了。實(shí)際上 code 這個關(guān)鍵字是51單片機(jī)特有的,如果是其它類型的單片機(jī)我們只需要寫成 const unsigned char LedChar[]={}就可以了,自動保存到 FLASH 里,而51單片機(jī)只用 const 而不加 code 的話,這個數(shù)組會保存到 RAM 中,而不會保存到 FLASH 中,鑒于此,在51這個體系下,const 反倒變得不那么重要了,它的作用被 code 取代了,這里大家知道這么回事即可。

我們來對各種類型的常量做進(jìn)一步說明。

整型常量和浮點(diǎn)型常量就沒多少可說的了,之前我們應(yīng)用的都很熟練了,整型直接寫數(shù)字就是十進(jìn)制如128,前邊 0x 開頭的表示是十六進(jìn)制 0x80,浮點(diǎn)型直接寫帶小數(shù)點(diǎn)的數(shù)據(jù)就可以了。

字符型常量是由一對單引號括起來的單個字符。它分為兩種形式,一種是普通字符,一種是轉(zhuǎn)義字符。

普通字符就是那些我們可以直接書寫直接看到的有形的字符,比如阿拉伯?dāng)?shù)字0~9,英文字符 A~z,以及標(biāo)點(diǎn)符號等。它們都是 ASCII 碼表中的字符,而它們在單片機(jī)中都占用一個字節(jié)的空間,其值就是對應(yīng)的 ASCII 碼值。比如?a?的值是97,?A?的值是65,?0?的值是48,如果定義一個變量 unsigned char a = ?a?,那么變量 a 的值就是97。

除了上述這些字符之外,還有一些特殊字符,它們一些是無形的,像回車符、換行符這些都是看不到的,還有一些像?\”這類字符它們已經(jīng)有特殊用途了,想象一下如果寫 '''覺得編譯器會怎么去解釋呢。針對這些特殊符號,為了可以讓它們正常進(jìn)入到我們的程序代碼中,C 語言就規(guī)定了轉(zhuǎn)義字符,它是以反斜杠()開頭的特定字符序列,讓它們來表示這些特殊字符,比如我們用 \n 來代表換行。我們用一個簡單表格來說明一下常用的轉(zhuǎn)義字符的意思,如表12-2所示。

表 12-2 常用轉(zhuǎn)義字符及含義

字符形式 含義
\n 換行
\t 橫向跳格(相當(dāng)于 Tab)
\v 豎向跳格
\b 退格
\r 光標(biāo)移到行首
\|反斜杠字符?\?
\? 單引號字符
\” 雙引號字符
\f 走紙換頁
\0 空值

表格不需要大家記住,用到了,過來查就可以了。

字符串常量是用雙引號括起來的字符序列,一般我們都稱之字符串。如“a”、“1234”、“welcome to www.kingst.org”等都是字符串常量。字符串常量在內(nèi)存中按順序逐個存儲字符串中的字符的 ASCII 碼值,并且特別注意,最后還有一個字符?\0?,?\0?字符的 ASCII 碼值是0,它是字符串結(jié)束標(biāo)志,在寫字符串的時候,這個?\0?是隱藏的,我們看不到,但是實(shí)際卻是存在的。所以“a”就比?a?多了一個 ?\0?,“a”的就占了2個字節(jié),而 ?a?只占一個字節(jié)。

還有一個地方要注意, 就是字符串中的空格, 也是一個字符,比如 “welcome to www.kingst.org ”一共占了26個字節(jié)的空間。其中21個字母,2個?.?,2個 ? ?(空格字符)以及一個?\0?。

字符和字符串?dāng)?shù)組實(shí)例

為了對比字符串、字符數(shù)組、常量數(shù)組的區(qū)別,我們寫個了簡單的演示程序,定義了4個數(shù)組分別是:

unsigned char array1[] = "1-Hello!\r\n";
unsigned char array2[] = {'2', '-', 'H', 'e', 'l', 'l', 'o', '!', '\r', '\n'};
unsigned char array3[] = {51, 45, 72, 101, 108, 108, 111, 33, 13, 10};
unsigned char array4[] = "4-Hello!\r\n";

在串口調(diào)試助手下,發(fā)送十六進(jìn)制的1、2、3、4,使用字符形式顯示的話,會分別往電腦上送這4個數(shù)組中對應(yīng)的那個數(shù)組。我們只是在起始位置做了區(qū)分,其它均沒有區(qū)別。大家可以比較一下效果。

此外還要說明一點(diǎn),數(shù)組1和數(shù)組4,數(shù)組1我們是發(fā)完整的字符串,而數(shù)組4我們僅僅發(fā)送數(shù)組中的字符,沒有發(fā)結(jié)束符號。串口調(diào)試助手用字符形式顯示是沒有區(qū)別的,但是大家如果改用十六進(jìn)制顯示,大家會發(fā)現(xiàn)數(shù)組1比數(shù)組4多了一個字節(jié)? \0 ?的 ASCII 值00。

#include <reg52.h>
bit cmdArrived = 0; //命令到達(dá)標(biāo)志,即接收到上位機(jī)下發(fā)的命令
unsigned char cmdIndex = 0; //命令索引,即與上位機(jī)約定好的數(shù)組編號
unsigned char cntTxd = 0; //串口發(fā)送計數(shù)器
unsigned char *ptrTxd; //串口發(fā)送指針

unsigned char array1[] = "1-Hello!\r\n";
unsigned char array2[] = {'2', '-', 'H', 'e', 'l', 'l', 'o', '!', '\r', '\n'};
unsigned char array3[] = {51, 45, 72, 101, 108, 108, 111, 33, 13, 10};
unsigned char array4[] = "4-Hello!\r\n";

void ConfigUART(unsigned int baud);
void main(){
    EA = 1; //開總中斷
    ConfigUART(9600); //配置波特率為 9600

    while (1){
        if (cmdArrived){
            cmdArrived = 0;
            switch (cmdIndex){
                case 1:
                    ptrTxd = array1; //數(shù)組1的首地址賦值給發(fā)送指針
                    cntTxd = sizeof(array1); //數(shù)組1的長度賦值給發(fā)送計數(shù)器
                    TI = 1; //手動方式啟動發(fā)送中斷,處理數(shù)據(jù)發(fā)送
                    break;
                case 2:
                    ptrTxd = array2;
                    cntTxd = sizeof(array2);
                    TI = 1;
                    break;
                case 3:
                    ptrTxd = array3;
                    cntTxd = sizeof(array3);
                    TI = 1;
                    break;
                case 4:
                    ptrTxd = array4;
                    cntTxd = sizeof(array4) - 1; //字符串實(shí)際長度為數(shù)組長度減1
                    TI = 1;
                    break;
                default:
                    break;
            }
        }
    }
}
/* 串口配置函數(shù),baud-通信波特率 */
void ConfigUART(unsigned int baud){
    SCON = 0x50; //配置串口為模式1
    TMOD &= 0x0F; //清零 T1 的控制位
    TMOD |= 0x20; //配置 T1 為模式2
    TH1 = 256 - (11059200/12/32)/baud; //計算 T1 重載值
    TL1 = TH1; //初值等于重載值
    ET1 = 0; //禁止 T1 中斷
    ES = 1; //使能串口中斷
    TR1 = 1; //啟動 T1
}
/* UART 中斷服務(wù)函數(shù) */
void InterruptUART() interrupt 4{
    if (RI){ //接收到字節(jié)
        RI = 0; //清零接收中斷標(biāo)志位
        cmdIndex = SBUF; //接收到的數(shù)據(jù)保存到命令索引中
        cmdArrived = 1; //設(shè)置命令到達(dá)標(biāo)志
    }
    if (TI){ //字節(jié)發(fā)送完畢
        TI = 0; //清零發(fā)送中斷標(biāo)志位
        if (cntTxd > 0){ //有待發(fā)送數(shù)據(jù)時,繼續(xù)發(fā)送后續(xù)字節(jié)
            SBUF = *ptrTxd; //發(fā)出指針指向的數(shù)據(jù)
            cntTxd--; //發(fā)送計數(shù)器遞減
            ptrTxd++; //發(fā)送指針遞增
        }
    }
}