久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 2630|回復: 34
打印 上一主題 下一主題
收起左側

C語言如何將多個位變量轉換成一個變量來存儲

  [復制鏈接]
跳轉到指定樓層
樓主
ID:34149 發表于 2024-1-17 12:19 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
平時利用多個按鍵,往往都是一個按鍵一個位變量表示,在單片機C語言中要么是0,要么是1,就好像按鍵一樣,
程序中為了判斷狀態,要寫很多語句,特別是多個按鍵的情況,占用很多程序空間。
為了計算方便,利用存儲空間,有沒有什么好辦法把他們集中在一起組成一個單字節的,判斷這個數值的內容,就能方便的
判斷出多個位變量的狀態。
比如有6個獨立按鍵,占用了分散的不同的IO口,每個按鍵都要用到短按、長按、組合等控制功能,如果每個按鍵都寫一次
這樣子的判斷,那么將有6個這樣子的似乎重復的語句,各種變量,大量占據存儲空間。

想請教各位老師,如何利用程序強大的運算功能,高效利用程序儲存空間,
有什么好的算法使這6個位變量通過哪種方法組合成一個單字節的變量。


分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏2 分享淘帖 頂 踩
回復

使用道具 舉報

沙發
ID:895440 發表于 2024-1-17 14:46 | 只看該作者
用bit類型
一個bit變量只占一位
回復

使用道具 舉報

板凳
ID:458247 發表于 2024-1-17 14:48 | 只看該作者
支持位帶操作的單片機可以用結構體位域寫法
回復

使用道具 舉報

地板
ID:883242 發表于 2024-1-17 16:08 | 只看該作者
不同平臺做法完全不一樣。

不支持位操作的單片機以及編譯器,只能用“位域”來實現,具體使用方法自己搜。

支持位操作的單片機及編譯器查手冊,以Keil C51為例,定義字節變量的時候加上bdata屬性,然后用sbit定義就行了。

  1. unsigned char bdata datum;
  2. sbit bd0=datum^0;
  3. sbit bd1=datum^1;
復制代碼
回復

使用道具 舉報

5#
ID:883242 發表于 2024-1-17 19:44 | 只看該作者
支持bit-band的ARM比如cortex-m3可以這么寫,不過不建議,bit-band訪問1位需要32位地址,如果不是特殊功能寄存器,只是通用內存,這生意太不劃算了。
  1. #define DEVICE_REG0 ((volatile unsigned long *) (0x40000000))
  2. #define DEVICE_REG0_BIT0 ((volatile unsigned long *) (0x42000000))
  3. #define DEVICE_REG0_BIT1 ((volatile unsigned long *) (0x42000004))
復制代碼
回復

使用道具 舉報

6#
ID:34149 發表于 2024-1-17 22:23 | 只看該作者
總共6個按鍵位變量,我把它合在一起了,成了一個字節,只是想讓它在后面的判斷和調用方便。沒想到還有點難處理。有了返回值,判斷起來就方便多了,組合判斷非常有優勢。
unsigned char KeyScan(unsigned char KeyFlag)
{
        static unsigned char da=0xff;
        if(KeyFlag==1)
        {
                if(key1==0)da &= 0xfe;else da |= 0x01;
                if(key2==0)da &= 0xfd;else da |= 0x02;
                if(key3==0)da &= 0xfb;else da |= 0x04;
                if(key4==0)da &= 0xf7;else da |= 0x08;
                if(key5==0)da &= 0xef;else da |= 0x16;
                if(key6==0)da &= 0xdf;else da |= 0x32;
         }
         return da;
}
回復

使用道具 舉報

7#
ID:883242 發表于 2024-1-18 01:43 | 只看該作者
dyx811 發表于 2024-1-17 22:23
總共6個按鍵位變量,我把它合在一起了,成了一個字節,只是想讓它在后面的判斷和調用方便。沒想到還有點難 ...

你這代碼轉換成機器碼,執行效率跟我在地板發的代碼差了十萬八千里,好好學習吧。
回復

使用道具 舉報

8#
ID:213173 發表于 2024-1-18 08:26 | 只看該作者
dyx811 發表于 2024-1-17 22:23
總共6個按鍵位變量,我把它合在一起了,成了一個字節,只是想讓它在后面的判斷和調用方便。沒想到還有點難 ...

假設6個按鍵分別接P2.3、2.4,P1.1~1.4
#define KeyFlag P2<<1&0x30|P1>>1&0x0f

unsigned char KeyScan(unsigned char da)
{
        switch(da)
        {
                case 0x3e: da=1; break;
                case 0x3d: da=2; break;
                case 0x3b: da=3; break;
                case 0x37: da=4; break;
                case 0x2f: da=5; break;
                case 0x1f: da=6; break;
                default:   da=0; break;
        }       
        return da;
}
回復

使用道具 舉報

9#
ID:1073939 發表于 2024-1-18 08:40 | 只看該作者
dyx811 發表于 2024-1-17 22:23
總共6個按鍵位變量,我把它合在一起了,成了一個字節,只是想讓它在后面的判斷和調用方便。沒想到還有點難 ...

你這段代碼可優化。節省一個全局變量,代碼也可簡短些。

  1. unsigned char KeyScan(unsigned char KeyFlag)
  2. {
  3.         unsigned char da=0xff;
  4.         if(KeyFlag==1)
  5.         {
  6.                 if(key1==0)da &= 0xfe;
  7.                 if(key2==0)da &= 0xfd;
  8.                 if(key3==0)da &= 0xfb;
  9.                 if(key4==0)da &= 0xf7;
  10.                 if(key5==0)da &= 0xef;
  11.                 if(key6==0)da &= 0xdf;
  12.          }
  13.          return da;
  14. }
復制代碼


回復

使用道具 舉報

10#
ID:458247 發表于 2024-1-18 08:57 | 只看該作者
wulin 發表于 2024-1-18 08:26
假設6個按鍵分別接P2.3、2.4,P1.1~1.4
#define KeyFlag P21&0x0f

typedef struct
{
    unsigned int key1 : 1;
    unsigned int key2 : 1;
    unsigned int key3 : 1;
    unsigned int key4 : 1;
    unsigned int key5 : 1;
    unsigned int key6 : 1;
}TsMAIN_h_KeyValueStatType;

typedef union
{
    TsMAIN_h_KeyValueStatType keyStat;
    unsigned char             keyValue;
}TuMAIN_h_KeyValueUnionType;

TuMAIN_h_KeyValueUnionType SsMAIN_h_KeyValue;

unsigned char GetKeyValue( unsigned char KeyFlag )
{
    if( 1== KeyFlag )
    {
        SsMAIN_h_KeyValue.keyStat.key1 = (!key1) ? 0 : 1;
        SsMAIN_h_KeyValue.keyStat.key2 = (!key2) ? 0 : 1;
        SsMAIN_h_KeyValue.keyStat.key3 = (!key3) ? 0 : 1;
        SsMAIN_h_KeyValue.keyStat.key4 = (!key4) ? 0 : 1;
        SsMAIN_h_KeyValue.keyStat.key5 = (!key5) ? 0 : 1;
        SsMAIN_h_KeyValue.keyStat.key6 = (!key6) ? 0 : 1;
    }
}
回復

使用道具 舉報

11#
ID:458247 發表于 2024-1-18 09:19 | 只看該作者
yzw846562238 發表于 2024-1-18 08:57
typedef struct
{
    unsigned int key1 : 1;

return SsMAIN_h_KeyValue.KeyValue;
回復

使用道具 舉報

12#
ID:883242 發表于 2024-1-18 14:28 | 只看該作者
yzw846562238 發表于 2024-1-18 08:57
typedef struct
{
    unsigned int key1 : 1;

這算是個通用的做法,在有特殊位尋址功能的平臺上,比如51的效率就非常差勁了。

加強知識的學習吧。
回復

使用道具 舉報

13#
ID:485350 發表于 2024-1-18 15:34 | 只看該作者
void Key_Scan()                //按鍵檢測 1ms調用
{
        u8 i;
        u8 Loop_Bit = 0x01;
    u8 Key = 0;
       
        if(KEY1_IO == 0)
        {
                Key |= KEY_BIG;
    }
   
    if(KEY2_IO == 0)
        {
                Key |= KEY_SMALL;
    }
   
        for(i = 0; i < KEYNUM; i++)
        {
                if((Key_Lock & Loop_Bit) == 0)                                                        //唯一按鍵
                {
                        if(Key & Loop_Bit)
                        {
                                if(++Key_Count[i] >= 50)                        //消抖50ms
                                {
                                        Key_Count[i] = 0;
                                        Key_Down |= Loop_Bit;        //按鍵觸發
                                        Key_Lock |= Loop_Bit;                        //按鍵鎖住         
                                }
                        }
                        else
                        {
                                Key_Count[i] = 0;
                        }
                }
                else
                {
                        if((Key & Loop_Bit) == 0)
                        {
                                if(++Key_Count[i] >= 40)                        //消抖50ms
                                {
                                        Key_Count[i] = 0;
                                        Key_Lock &= ~Loop_Bit;                        //按鍵鎖解除
                                        Key_Up |= Loop_Bit;
                                }
                        }
                        else
                        {
                                Key_Count[i] = 0;
                        }
                }
                Loop_Bit <<= 1;
        }
}
回復

使用道具 舉報

14#
ID:34149 發表于 2024-1-18 17:22 | 只看該作者
ydatou 發表于 2024-1-18 08:40
你這段代碼可優化。節省一個全局變量,代碼也可簡短些。

利用了靜態變量可以不用每次都初始化da,這樣子不能做多鍵同時按下的準確判斷。
回復

使用道具 舉報

15#
ID:34149 發表于 2024-1-18 17:35 | 只看該作者
yzw846562238 發表于 2024-1-18 09:19
return SsMAIN_h_KeyValue.KeyValue;

差點以為結構體可以自動返回呢,不過這種寫法看的頭暈。變量名字好長好長。但是非常的新穎!
現在就去驗證該語句對空間占用,機器周期耗費情況。
回復

使用道具 舉報

16#
ID:34149 發表于 2024-1-18 17:57 | 只看該作者
wulin 發表于 2024-1-18 08:26
假設6個按鍵分別接P2.3、2.4,P1.1~1.4
#define KeyFlag P21&0x0f

這個還沒有看得懂。同時按住兩個按鍵返回值是如何變化的呢 ?
回復

使用道具 舉報

17#
ID:34149 發表于 2024-1-18 18:02 | 只看該作者
Hephaestus 發表于 2024-1-18 01:43
你這代碼轉換成機器碼,執行效率跟我在地板發的代碼差了十萬八千里,好好學習吧。

一定好好學習。主要是高級點的單片機還沒有咋個會呢。你發的代碼是帶指針的嗎?一時半會還理解不透。

事實上,我是想把一堆的位變量,(我舉的例子是6個,來自于不同的地方),放在一個字節里面,用8位分別代表其中各位的狀態,方便后期僅對該字節的判斷就知道哪些位有效,哪些組合滿足要求,同時還有濾波,長按的判斷等等。主要目的是不用分別對每個位變量判斷短按長按等等。
回復

使用道具 舉報

18#
ID:34149 發表于 2024-1-18 19:53 | 只看該作者
18680365301 發表于 2024-1-18 15:34
void Key_Scan()                //按鍵檢測 1ms調用
{
        u8 i;

這是咋玩的啊,開頭幾句就卡殼了
回復

使用道具 舉報

19#
ID:883242 發表于 2024-1-18 22:27 | 只看該作者
dyx811 發表于 2024-1-18 18:02
一定好好學習。主要是高級點的單片機還沒有咋個會呢。你發的代碼是帶指針的嗎?一時半會還理解不透。

...

8051內存地址20h~27h這8個字節每位都是可以直接訪問的,具體使用方法參加我在地板位的代碼。
回復

使用道具 舉報

20#
ID:624769 發表于 2024-1-18 23:05 | 只看該作者
dyx811 發表于 2024-1-17 22:23
總共6個按鍵位變量,我把它合在一起了,成了一個字節,只是想讓它在后面的判斷和調用方便。沒想到還有點難 ...

sbit Temp1 = ACC^0;
sbit Temp2 = ACC^1;
sbit Temp3 = ACC^2;
sbit Temp4 = ACC^3;
sbit Temp5 = ACC^4;
sbit Temp6 = ACC^5;

unsigned char KeyScan(unsigned char KeyFlag)
{
        ACC = 0xff;
        if(KeyFlag==1)
        {
                Temp1 = key1;
                Temp2 = key2;
                Temp3 = key3;
                Temp4 = key4;
                Temp5 = key5;
                Temp6 = key6;
         }
         return ACC;
}
回復

使用道具 舉報

21#
ID:883242 發表于 2024-1-18 23:59 | 只看該作者
188610329 發表于 2024-1-18 23:05
sbit Temp1 = ACC^0;
sbit Temp2 = ACC^1;
sbit Temp3 = ACC^2;

你的代碼太想當然了。

        ACC = 0xff;
        if(KeyFlag==1)
后面這一句執行的時候,前面那一句的結果已經被破壞掉了。
回復

使用道具 舉報

22#
ID:1073939 發表于 2024-1-19 14:29 | 只看該作者
dyx811 發表于 2024-1-18 17:22
利用了靜態變量可以不用每次都初始化da,這樣子不能做多鍵同時按下的準確判斷。

請仔細分析下我給你的優化代碼。
1:因為有這變量的初始換,才省了你代碼中的一堆else。
2:臨時變量和全局變量相比,代碼空間更小,執行速度更快。計算越復雜,用臨時變量優化效果越明顯。你就是一定要使用全局變量,也應該先用臨時變量獲得計算結果,之后賦值給全局變量。
3.靜態變量是全局變量的一種,但限制了使用范圍。從你的代碼看,使用靜態變量無意義。
回復

使用道具 舉報

23#
ID:34149 發表于 2024-1-19 15:33 | 只看該作者
ydatou 發表于 2024-1-19 14:29
請仔細分析下我給你的優化代碼。
1:因為有這變量的初始換,才省了你代碼中的一堆else。
2:臨時變量和 ...

謝謝指點,突然恍然大悟了!!我居然把把&運算算錯了。。。光想著怎么復原該Bit位了。
這樣子確實精簡了好多代碼。非常感謝。
回復

使用道具 舉報

24#
ID:883242 發表于 2024-1-19 16:23 | 只看該作者
dyx811 發表于 2024-1-19 15:33
謝謝指點,突然恍然大悟了!!我居然把把&運算算錯了。。。光想著怎么復原該Bit位了。
這樣子確實精簡了 ...

都不對。

代碼是否被簡化,以c語言的簡潔程度來判斷是錯誤的。

只有匯編碼,也就單片機執行的機器碼,變簡潔了,才是真的優化。

你們搞的都是假優化。

評分

參與人數 1黑幣 +5 收起 理由
dzbj + 5 贊一個!

查看全部評分

回復

使用道具 舉報

25#
ID:1073939 發表于 2024-1-19 16:36 | 只看該作者
ydatou 發表于 2024-1-19 14:29
請仔細分析下我給你的優化代碼。
1:因為有這變量的初始換,才省了你代碼中的一堆else。
2:臨時變量和 ...

再看了下樓主代碼,當KeyFlag 不為1時,要返回上一次的key值,這確實需要一個全局變量,我給的優化代碼沒做到這點。
修改如下
  1. unsigned char KeyScan(unsigned char KeyFlag)
  2. {
  3.         static unsigned char old=0xff;
  4.         if (KeyFlag == 1)
  5.         {
  6.                 unsigned char da = 0xff;
  7.                 if (key1 == 0)
  8.                         da &= 0xfe;
  9.                 if (key2 == 0)
  10.                         da &= 0xfd;
  11.                 if (key3 == 0)
  12.                         da &= 0xfb;
  13.                 if (key4 == 0)
  14.                         da &= 0xf7;
  15.                 if (key5 == 0)
  16.                         da &= 0xef;
  17.                 if (key6 == 0)
  18.                         da &= 0xdf;
  19.                 old=da;
  20.         }
  21.         return old;
  22. }
復制代碼


假如是使用51MCU,使用位變量更好,如下
  1. unsigned char bdata gKey = 0xff;
  2. sbit bKey1 = gKey ^ 0;
  3. sbit bKey2 = gKey ^ 1;
  4. sbit bKey3 = gKey ^ 2;
  5. sbit bKey4 = gKey ^ 3;
  6. sbit bKey5 = gKey ^ 4;
  7. sbit bKey6 = gKey ^ 5;
  8. unsigned char KeyScan(unsigned char KeyFlag)
  9. {
  10.         if (KeyFlag == 1)
  11.         {
  12.                 bKey1 = key1;
  13.                 bKey2 = key2;
  14.                 bKey3 = key3;
  15.                 bKey4 = key4;
  16.                 bKey5 = key5;
  17.                 bKey6 = key6;
  18.         }
  19.         return gKey;
  20. }
復制代碼


回復

使用道具 舉報

26#
ID:34149 發表于 2024-1-20 21:22 | 只看該作者
ydatou 發表于 2024-1-19 16:36
再看了下樓主代碼,當KeyFlag 不為1時,要返回上一次的key值,這確實需要一個全局變量,我給的優化代碼沒 ...

bdta太好用了!不光完全實現了一堆位變量的整合,經過實驗,不光實現了既定要求,程序上還節省了大量空間。
我采用了  ydatou 大哥的編程思路,簡單,高效!
在此,感謝各位大佬們的熱心幫助!
期望大家在單片機領域有更深的造詣,在編程道路上技術越來越精湛!
祝愿各位在龍年   {“龍騰虎躍!心想事成!”}

回復

使用道具 舉報

27#
ID:883242 發表于 2024-1-20 21:38 | 只看該作者
dyx811 發表于 2024-1-20 21:22
bdta太好用了!不光完全實現了一堆位變量的整合,經過實驗,不光實現了既定要求,程序上還節省了大量空間 ...

我早就告訴你了你不看。
回復

使用道具 舉報

28#
ID:196791 發表于 2024-1-21 00:34 來自手機 | 只看該作者
學習各大佬的編程思路,深受啟發
回復

使用道具 舉報

29#
ID:1101997 發表于 2024-1-21 08:31 | 只看該作者
我們追求效率肯定是沒有錯的。對于現在的處理器來說,內存空間和運行速度基本上都是能滿足一般運行要求的,對于項目來說,可靠健壯的代碼和清晰明了的結構,是當前需要重點關注的。
回復

使用道具 舉報

30#
ID:1101997 發表于 2024-1-21 08:34 | 只看該作者
我們追求效率肯定是沒有錯的。
對于現在的處理器來說,內存空間和運行速度基本上都是能滿足一般運行要求的,對于項目來說,可靠健壯的代碼和清晰明了的文件架構,也許我們需要更重點關注的。

回復

使用道具 舉報

31#
ID:420836 發表于 2024-1-21 09:06 | 只看該作者
一個字節由 8 位組成。 字節的按位操作廣泛用于數字變量,例如開關狀態、標志和數字輸出。
回復

使用道具 舉報

32#
ID:883242 發表于 2024-1-21 12:31 | 只看該作者
TTQ001 發表于 2024-1-21 09:06
一個字節由 8 位組成。 字節的按位操作廣泛用于數字變量,例如開關狀態、標志和數字輸出。

字節的概念多了去了,早年計算機一個字節6、7、8位的都有,TI C2000系列DSP一個字節16位,不存在8位操作,你還是見識的太少了。
回復

使用道具 舉報

33#
ID:34149 發表于 2024-1-21 18:12 | 只看該作者
Hephaestus 發表于 2024-1-20 21:38
我早就告訴你了你不看。

我看了,當時沒有想到能這么用。主要看來還是學習少了!
以后定向大佬們學習!請受小弟一拜!!!!
回復

使用道具 舉報

34#
ID:849913 發表于 2024-2-9 22:58 | 只看該作者
可以 用一個8位的io端口啊 用6位 寫程序時判斷io端口的狀態 如P1=0xc0 就是“”11000000“” 就是一起按了6個按鍵
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

手機版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 免费午夜视频 | 一区二区三区免费 | 国产区精品 | 一级黄色片日本 | 99精品网站 | 99成人精品 | 综合久 | 农村黄性色生活片 | 国产精品视频免费观看 | 国产精品久久国产精品久久 | 精品欧美二区 | 天堂一区二区三区 | 野狼在线社区2017入口 | 久久精品这里 | 欧美久久影院 | 毛片国产 | 日韩欧美在 | 国产精品成av人在线视午夜片 | av激情在线 | 国产精品不卡一区 | 亚洲看片网站 | 亚洲欧美日韩精品 | 亚洲在线 | 国产在线视频一区 | 伊人超碰| 二区中文 | 精品国产乱码久久久久久图片 | 欧美三级在线 | 久久男人天堂 | 91精品国产综合久久久久 | 怡红院成人在线视频 | 亚洲精品乱码久久久久久按摩观 | 五月综合激情网 | 精品一区二区三区在线观看 | 国产日韩一区 | 婷婷福利视频导航 | 欧美精品一区二区三区在线播放 | 久久三区 | 久草新在线 | 成人欧美一区二区三区黑人孕妇 | 亚洲国产精品久久人人爱 |