亚洲春色中文字幕久久久-三上亚,一吻二脱三床四吻胸,国产真实伦对白视频全集,在线毛片观看,精品成品入口黄网,国产毛aⅴ片久久久,亚洲AV色香蕉一区二区三区老师,萧皇后A级艳片,色情日本视频更新,99久久亚洲精品日本无码

標(biāo)題: 第11章 指針基礎(chǔ)與串口實(shí)用程序11.1 [打印本頁]

作者: 卓然塵世間    時(shí)間: 2026-4-23 10:10
標(biāo)題: 第11章 指針基礎(chǔ)與串口實(shí)用程序11.1
指針是C語言最核心的部分,而UART串口通信是單片機(jī)最常用的一種通信方式。因此這兩部分內(nèi)容,除了在第10章進(jìn)行簡(jiǎn)單的介紹外,本章還需要進(jìn)一步加深學(xué)習(xí),用實(shí)用的例子來不斷增強(qiáng)對(duì)于這兩部分內(nèi)容的理解和應(yīng)用能力。11.1指向數(shù)組元素的指針
11.1.1
指向數(shù)組元素的指針和運(yùn)算法則
所謂指向數(shù)組元素的指針,其本質(zhì)還是變量的指針。因?yàn)閿?shù)組中的每個(gè)元素,其實(shí)都可以直接看成是一個(gè)變量,所以指向數(shù)組元素的指針,也就是變量的指針。
指向數(shù)組元素的指針不難,但很常用。
    unsigned char number[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    unsigned char *p;
如果寫p = &number[0];那么指針p就指向了number的第0號(hào)元素,也就是把number[0]的地址賦值給了p,同理,如果寫p = &number[1];p就指向了數(shù)組number的第1號(hào)元素。p = &number[x];其中x的取值范圍是09,就表示p指向了數(shù)組number的第x號(hào)元素。
指針本身,也可以進(jìn)行幾種簡(jiǎn)單的運(yùn)算,這幾種運(yùn)算對(duì)于數(shù)組元素的指針來說應(yīng)用最多。
1、比較運(yùn)算。比較的前提是兩個(gè)指針指向同種類型的對(duì)象,比如兩個(gè)指針變量pq它們指向了具有同種數(shù)據(jù)類型的數(shù)組,那它們可以進(jìn)行<>>=<===等關(guān)系運(yùn)算。如果p==q為真的話,表示這兩個(gè)指針指向的是同一個(gè)元素。
2、指針和整數(shù)可以直接進(jìn)行加減運(yùn)算。比如還是前邊講的指針p和數(shù)組number,如果p = &number[0],那么p+1就指向了number[1]p+9就指向了number[9]。當(dāng)然了,如果p = &number[9]p-9也就指向了number[0]
3、兩個(gè)指針變量在一定條件下可以進(jìn)行減法運(yùn)算。如p = &number[0]; q = &number[9];那么q-p的結(jié)果就是9。這個(gè)地方要特別注意,這個(gè)9代表的是元素的個(gè)數(shù),而不是真正的地址差值。如果number的變量類型是unsigned int型,占2個(gè)字節(jié),q-p的結(jié)果依然是9,因?yàn)樗淼氖菙?shù)組元素的個(gè)數(shù)。
在數(shù)組元素指針這里還有一種情況,數(shù)組名字就代表了數(shù)組元素的首地址,也就是說:
    p = &number[0];
    p = number;
這兩種表達(dá)方式是等價(jià)的,因此以下幾種表達(dá)形式和內(nèi)容需要格外注意一下。
根據(jù)指針的運(yùn)算規(guī)則,p+x代表的是number[x]的地址,那么number+x代表的也是number[x]的地址。或者說,它們指向的都是number數(shù)組的第x號(hào)元素。
*(p+x)*(number+x)都表示number[x]
指向數(shù)組元素的指針也可以表示成數(shù)組的形式,也就是說,允許指針變量帶下標(biāo),即p[ i]*(p+i)是等價(jià)的。為了避免混淆,這里建議不要寫成前者,而一律采用后者的寫法。
[i ]二維數(shù)組元素的指針和一維數(shù)組類似,需要介紹的內(nèi)容不多。假如現(xiàn)在一個(gè)指針變量p和一個(gè)二維數(shù)組number[3][4],它的地址的表達(dá)方式也就是p=&number[0][0],有一個(gè)地方要注意,既然數(shù)組名代表了數(shù)組元素的首地址,那么也就是說pnumber都是指數(shù)組的首地址。對(duì)二維數(shù)組來說,number[0]number[1]number[2]都可以看成是一維數(shù)組的數(shù)組名字,所以number[0]等價(jià)于&number[0][0]number[1]等價(jià)于&number[1][0]number[2]等價(jià)于&number[2][0]。加減運(yùn)算和一維數(shù)組是類似的,不再詳述。
[i ]11.1.2 數(shù)組元素指針的實(shí)例
C語言里邊,sizeof()可用來獲取括號(hào)內(nèi)對(duì)象所占用的字節(jié)數(shù),雖然寫函數(shù)形式,但它不是一個(gè)函數(shù),而是C語言的一個(gè)關(guān)鍵字,sizeof()在程序中相當(dāng)于一個(gè)常量,也就是說這個(gè)獲取操作是在程序編譯的時(shí)候進(jìn)行的,而不是在程序運(yùn)行的時(shí)候進(jìn)行。這是一個(gè)實(shí)際編程中很有用的關(guān)鍵字,靈活運(yùn)用它可以為程序帶來更好的可讀性、易維護(hù)性和可移植性。
sizeof()括號(hào)中可以是變量名,也可以是變量類型名。而其更大的用處是與數(shù)組名搭配使用,可以獲取整個(gè)數(shù)組占用的字節(jié)數(shù),不用自己動(dòng)手計(jì)算了,可以避免錯(cuò)誤,而如果日后改變了數(shù)組的維數(shù)時(shí),也不需要執(zhí)行代碼中逐個(gè)修改,便于程序的維護(hù)和移植。
下面提供一個(gè)簡(jiǎn)單的串口演示例程,可以體驗(yàn)一下指針和sizeof()的用法。例程首先接收上位機(jī)下發(fā)的命令,根據(jù)命令值分別把不同數(shù)組的數(shù)據(jù)回發(fā)給上位機(jī),程序還用到了指針的自增運(yùn)算,也就是+1運(yùn)算,體會(huì)一下指針ptrTxd在串口發(fā)送的過程中的指向是如何變化的。在上位機(jī)串口調(diào)試助手中分別下發(fā)1234,就會(huì)得到不同的數(shù)組回發(fā),注意這里都用十六進(jìn)制發(fā)送和十六進(jìn)制顯示。
此外,前邊講了串口發(fā)送中斷標(biāo)志位TI是硬件置位,軟件清零的。通常來講,如果想一次發(fā)送多個(gè)數(shù)據(jù)的時(shí)候,就需要把第一個(gè)字節(jié)寫入SBUF,然后再等待發(fā)送中斷,在后續(xù)中斷中再發(fā)送剩余的數(shù)據(jù),這樣數(shù)據(jù)發(fā)送過程就被拆分到了兩個(gè)地方——主循環(huán)內(nèi)和中斷服務(wù)函數(shù)內(nèi),無疑就使得程序結(jié)構(gòu)變得零散了。這個(gè)時(shí)候,為了使程序結(jié)構(gòu)盡量緊湊,在啟動(dòng)發(fā)送的時(shí)候,不是向SBUF中寫入第一個(gè)待發(fā)的字節(jié),而是直接讓TI=1,注意,這時(shí)候會(huì)馬上進(jìn)入串口中斷,因?yàn)橹袛鄻?biāo)志位置1了,但是串口線上并沒有發(fā)送任何數(shù)據(jù)。于是,所有的數(shù)據(jù)發(fā)送都可以在中斷中進(jìn)行,而不用再分為兩部分了。
#include <reg52.h>
bit cmdArrived = 0;   //命令到達(dá)標(biāo)志,即接收到上位機(jī)下發(fā)的命令
unsigned char cmdIndex = 0; //命令索引,即與上位機(jī)約定好的數(shù)組編號(hào)
unsigned char cntTxd = 0;   //串口發(fā)送計(jì)數(shù)器
unsigned char *ptrTxd;      //串口發(fā)送指針
unsigned char array1[1] = {1};
unsigned char array2[2] = {1,2};
unsigned char array3[4] = {1,2,3,4};
unsigned char array4[8] = {1,2,3,4,5,6,7,8};
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的長(zhǎng)度賦值給發(fā)送計(jì)數(shù)器
                    TI = 1;   //手動(dòng)方式啟動(dòng)發(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);
                    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;  //計(jì)算T1重載值
    TL1 = TH1;     //初值等于重載值
    ET1 = 0;       //禁止T1中斷
    ES  = 1;       //使能串口中斷
    TR1 = 1;       //啟動(dòng)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ù)時(shí),繼續(xù)發(fā)送后續(xù)字節(jié)
        {
            SBUF = *ptrTxd;  //發(fā)出指針指向的數(shù)據(jù)
            cntTxd--;         //發(fā)送計(jì)數(shù)器遞減
            ptrTxd++;         //發(fā)送指針遞增
        }
    }
}
采用邏輯分析儀將4次收發(fā)數(shù)據(jù)全部抓出來,直觀的做一下對(duì)比,如圖11-1所示。

11-1 邏輯分析儀抓取串口數(shù)據(jù)數(shù)據(jù)





歡迎光臨 (http://www.denmoz.com/bbs/) Powered by Discuz! X3.1