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

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 5275|回復: 43
收起左側

想判斷一個數中"1"的個數的多少,有沒有什么高效的算法

  [復制鏈接]
ID:401564 發表于 2022-9-22 22:08 | 顯示全部樓層 |閱讀模式
最近在搞一個擇多算法,用于無刷電機的過零檢測,參考了PIC的代碼,原理大概是這樣的
每10uS讀取一次過零端口的狀態,然后把端口的電平保存,并左移一位,然后再進行比較,檢測這個數里面1的位是多少,用來檢測當前端口的電平,實際上就是一個濾波
if(IO) a |=0x01;
a <= 1;
a是個8位數,這樣一來,在讀取8次之后, a 就是一個完整的8次的IO狀態了
我就想知道,有沒有什么高效的算法,能快速的檢測 a 里面"1"有多少個,或者是說,快速判斷 a 里面"1"的個數超過6個
這個又不能用比大小,因為可能會出現這種情況: 0111 1111 或者是 1111 1110,或者其它的組合
這兩種情況都是超過了6個"1"的
PIC的方法是只比較3個位,用的是數組的方式,但這種方法在低轉速的時候,有時候會檢測到假的過零事件
先謝謝了
有什么其它關于無刷電機知識的,也可以相互探討一下
回復

使用道具 舉報

ID:688692 發表于 2022-9-22 23:50 | 顯示全部樓層
這個不就是查表的事情嗎,常規256字節的表,半字節4位查就是16字節的表
回復

使用道具 舉報

ID:883242 發表于 2022-9-23 00:33 | 顯示全部樓層
計算一個32位數字x含有1的個數:
  1. x = (x & 0x55555555) + ((x >> 1) & 0x55555555);
  2. x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
  3. x = (x & 0x0F0F0F0F) + ((x >> 4) & 0x0F0F0F0F);
  4. x = (x & 0x00FF00FF) + ((x >> 8) & 0x00FF00FF);
  5. x = (x & 0x0000FFFF) + ((x >> 16) & 0x0000FFFF);
復制代碼


在 Hacker's Delight 2nd Edition一書的§5.1,你自己看去吧。
回復

使用道具 舉報

ID:624769 發表于 2022-9-23 01:40 | 顯示全部樓層
if(IO)
{
a |=0x01;
b++;
}
a <= 1;

直接判斷 if(b>=6)  不行么?
回復

使用道具 舉報

ID:844772 發表于 2022-9-23 08:46 | 顯示全部樓層
還真沒想出太好的辦法,對于數位數,我是這么弄的:Count=(a&0x80)+(a&0x40)+...+(a&0x01)  然后看看Count是幾了。還有人直接位運算但我老是編譯不過。
回復

使用道具 舉報

ID:161164 發表于 2022-9-23 09:49 | 顯示全部樓層
  1. // **********************************************
  2. u8 bdata CompDat = 0;
  3. sbit Data0 = CompDat^0;
  4. sbit Data1 = CompDat^1;
  5. sbit Data2 = CompDat^2;
  6. sbit Data3 = CompDat^3;
  7. sbit Data4 = CompDat^4;
  8. sbit Data5 = CompDat^5;
  9. sbit Data6 = CompDat^6;
  10. sbit Data7 = CompDat^7;
  11. u8 CountBit1(u8 Dat)
  12. {
  13.         u8 Result = 0;
  14.         CompDat = Dat;
  15.         if(Data0)Result++;
  16.         if(Data1)Result++;
  17.         if(Data2)Result++;
  18.         if(Data3)Result++;
  19.         if(Data4)Result++;
  20.         if(Data5)Result++;
  21.         if(Data6)Result++;
  22.         if(Data7)Result++;
  23.         
  24.         return Result;
  25. }
  26. // **********************************************
  27. u8 CountBit2(u8 Dat)
  28. {
  29.         u8 Result = 0, Mask;
  30.         for(Mask = 0x01;Mask!=0;Mask<<=1)
  31.         {
  32.                 if(Dat&Mask)Result++;
  33.         }
  34.         return Result;
  35. }
復制代碼
STC89C仿真結果
2022-09-23_094250.png

2022-09-23_093905.png

2022-09-23_094123.png



STC15W仿真結果
2022-09-23_094457.png


2022-09-23_094426.png


2022-09-23_094438.png


回復

使用道具 舉報

ID:796531 發表于 2022-9-23 09:53 | 顯示全部樓層
在 if(IO)  后加一個語句,新增一個統計變量 然后自增, count++; ,滿8次后等你賦值a=0時同時把count=0;不就解決了,沒必要在后面再去計算吧
回復

使用道具 舉報

ID:88256 發表于 2022-9-23 10:01 | 顯示全部樓層

這個簡單的方法我昨晚看帖就冒出來了,樓主不可能想不出來,我估計樓主是要判斷已經生成后的a,也就是判斷任意一個數(一個字節)里1的個數,要極簡的方法我沒想到。
回復

使用道具 舉報

ID:161164 發表于 2022-9-23 10:17 | 顯示全部樓層
cnos 發表于 2022-9-22 23:50
這個不就是查表的事情嗎,常規256字節的表,半字節4位查就是16字節的表

查表真的快
2022-09-23_101226.png



2022-09-23_101239.png



2022-09-23_101253.png



字節592-586=6步
半字節607-592=15
回復

使用道具 舉報

ID:1045628 發表于 2022-9-23 10:56 | 顯示全部樓層
肯定是要一個中間變量來計算的,一個是和樓上一樣,每次進行a判斷時b自增,要么就最后用循環判斷a
for(i;i<8;i++)
{
    if(((a >> i) & 0x01) != 0)
    {
        b++;
    }
}
回復

使用道具 舉報

ID:1034262 發表于 2022-9-23 11:27 | 顯示全部樓層
查表最快,我常用到這個判斷,類似權重濾波。256個字節的表而已。
回復

使用道具 舉報

ID:839438 發表于 2022-9-23 11:58 | 顯示全部樓層
int bitcount (unsigned int n)
{
    int count=0 ;
    while (n) {
        count++ ;
        n &= (n - 1) ;
    }
    return count ;
}
這是我前段時間在另外一個論壇上看到的 作者是 cnxh  
回復

使用道具 舉報

ID:624769 發表于 2022-9-23 12:00 | 顯示全部樓層
hhdsdy 發表于 2022-9-23 10:01
這個簡單的方法我昨晚看帖就冒出來了,樓主不可能想不出來,我估計樓主是要判斷已經生成后的a,也就是判 ...

因為,任何其他可能用的方法, 都不會比  if(IO)  的時候,順便 b++ 來的更 “簡” , 所以,我才探討性的,問一下摟主,是基于什么原因,不能用這個方式。我從來沒有認為摟主想不出這個方法。
回復

使用道具 舉報

ID:1007932 發表于 2022-9-23 13:57 | 顯示全部樓層
  1. if(IO){
  2.         a|=0x01;
  3.         cnt++;
  4. }
  5. if(a&0x80) cnt--;
  6. a=a<<1;
復制代碼
回復

使用道具 舉報

ID:429003 發表于 2022-9-23 14:00 | 顯示全部樓層
統計數據data中1的個數:counter = 0;  while(data)  {  data &= data - 1; counter++;  },循環次數等于置1位的個數,代碼實現,除了查表想不出比這個效率高的方法了。
回復

使用道具 舉報

ID:332444 發表于 2022-9-23 14:47 | 顯示全部樓層
如果a不是數組的話可以判斷a是否=127即可就這么簡單,a可以這樣去算,a=0;if(a==0)++a;else a=a*2+1;
回復

使用道具 舉報

ID:236035 發表于 2022-9-23 16:32 | 顯示全部樓層
要高效嵌入匯編,C的位操作不方便。
回復

使用道具 舉報

ID:248705 發表于 2022-9-23 17:39 | 顯示全部樓層
Hephaestus 發表于 2022-9-23 00:33
計算一個32位數字x含有1的個數:

相見恨晚的神書啊,好兄弟好兄弟好兄弟
回復

使用道具 舉報

ID:248705 發表于 2022-9-23 17:49 | 顯示全部樓層
Hephaestus 發表于 2022-9-23 00:33
計算一個32位數字x含有1的個數:

此書中文譯本
hacker's delight(中文版)
自行網上搜索獲取

回復

使用道具 舉報

ID:401564 發表于 2022-9-23 22:28 | 顯示全部樓層

是我沒有把問題說清楚,不好意思了
這是一個過零檢測的濾波算法,因為在過零的時候,會有波動,比較器會一下子輸出1,一下輸出0
那么我現在要做的就是檢測出實際的過零的時間,就是說檢測比較器什么時候是"真實的從0變成了1"
這中間的過程大概是這樣子的吧:000000000   10101010110110  111111111
中間那一段就是波動的時候
你不能簡單的累計有多少個1,比如我定時器定時是10uS,如果都累加的話,當條件符合的時候,距離的真實過零點已經過去了60uS這在無刷電機中時間太長了
擇多算法真實的過程是這樣的:每次都比較一下這個數中和0和1
當出現這種情況時,就判定為過零:前面的數有超過一半是0的,后面的數超過一半是1的,就認為是有效的一次從0變成1的過程
有時間你可以看一下這里面的算法,后面部分有代碼,我只是想升級一下而已
01175a_cn.pdf (512.2 KB, 下載次數: 24)
回復

使用道具 舉報

ID:236035 發表于 2022-9-24 08:37 | 顯示全部樓層
如果有現成算法,那意味著大部分人都已經無法升級這個算法,除非是數學天才。
回復

使用道具 舉報

ID:491577 發表于 2022-9-24 09:51 | 顯示全部樓層
對于過零檢測我用外部中斷IO口檢測,IO口有跳變馬上進入中斷,反應最快,比定時檢測快。
回復

使用道具 舉報

ID:123289 發表于 2022-9-24 10:08 | 顯示全部樓層
1、一個方案是有0:則作過0處理。響應快,易受干擾。
2、另個方案是,出0后,再有連續N個1:則作過0處理。響應慢,不易受干擾。當N=1時,就是方案一。
樓主可以根據設計的目的,選擇N。
另一個要間,是采樣的間隔時間。

回復

使用道具 舉報

ID:401564 發表于 2022-9-24 22:52 | 顯示全部樓層
hhh402 發表于 2022-9-24 09:51
對于過零檢測我用外部中斷IO口檢測,IO口有跳變馬上進入中斷,反應最快,比定時檢測快。

那是有霍爾的
沒有霍爾的,哪能一有中斷就處理呀
換相一次之后馬上就有一次中斷了,如果是低轉速有電機,電感量會大點,能有三四的假過零
再到真實過零的時候,新西達電機好點,一般只有一次或者兩次波動而已,其它的電機,能有全十多次過零事件
不濾波哪里行呀,IO中斷我也用過,感覺好像不怎么好,1萬/分之后就開始一頓一頓的,電流也開始莫名的大了,估計就是換相上面的問題
我都燒了快10片IRS2101S了,之前沒管列死的問題,估計就是中斷頻繁錯誤換相搞壞有,現在,加入死區控制了就好點了
回復

使用道具 舉報

ID:491577 發表于 2022-9-25 18:37 | 顯示全部樓層
過零檢測不準確那時硬件的問題,加一組低通濾波就可以解決,過零檢測必須是過零才發出信號,如果發出錯誤信號是硬件問題,更改硬件而不是改程序。單片機編程必須要懂硬件的,單純懂軟件不行。
回復

使用道具 舉報

ID:401564 發表于 2022-9-26 00:44 | 顯示全部樓層
hhh402 發表于 2022-9-25 18:37
過零檢測不準確那時硬件的問題,加一組低通濾波就可以解決,過零檢測必須是過零才發出信號,如果發出錯誤信 ...

不知道你有沒有做過無感無刷電機?
無感無刷電機過零點波動很大的,就算是加了一個104電容也是會有波動的
電容不能加太大了,不然過零滯后時間就太長了
轉速1萬多的電機,有的100uS就要換相了,人家商用電調連濾波電容都不加的
10萬轉速的話,過零濾波,PWM調整,換相,定時器計算都要在十幾uS之內完成了
所以,要速度快呀,像那種幾十行代碼的,低轉速還行,高轉速就不行了
論壇上有的程序,我試了,1萬以下轉速還行,超過就不行了
回復

使用道具 舉報

ID:491577 發表于 2022-9-26 10:14 | 顯示全部樓層
需要速度用STM32高主頻單片機。不過硬件不行靠軟件只能夠自己玩玩,電機能夠轉動而已,其他的就談不上了。
回復

使用道具 舉報

ID:624769 發表于 2022-9-26 12:00 | 顯示全部樓層
Y_G_G 發表于 2022-9-23 22:28
是我沒有把問題說清楚,不好意思了
這是一個過零檢測的濾波算法,因為在過零的時候,會有波動,比較器會一下 ...

大概的理解了你的目的. 你看對不對?
你定時器中斷, 每10us(假定時間) 讀一次 IO,存入變量 a, 變量 a 永遠只保存 最后8次的 IO 狀態, 然后,你希望通過分析 變量 a 知道, 最后8次 是否 有6個以上的1。

如果我上述理解正確的話,個人覺得應當從源頭直接開始分析,而不是去分析變量a, (由于你只說是參考PIC,不知道你實際用的什么單片機,我就當51吧,反正你能看明白)
a<<=1;
if(CY)   b--;
if(IO)
{
      a |= 0x01;
      b++;
}
// b的值永遠和  變量a中 1 的個數保持一致。
回復

使用道具 舉報

ID:401564 發表于 2022-9-26 17:10 | 顯示全部樓層
188610329 發表于 2022-9-26 12:00
大概的理解了你的目的. 你看對不對?
你定時器中斷, 每10us(假定時間) 讀一次 IO,存入變量 a, 變量 a 永 ...

不只是只要判斷有多少個1,還得判斷有多少個0,用來檢測IO從0變成1的一個點
或者是從1變成0
實際上就是上升沿和下降沿檢測
但因為速度要求太高,而且IO波動過大,又不能漏掉太多,不然會錯過"真實的"過零點,處理時間并不多,就不能用什么復雜的算法
當然,這個是現在暫時用的辦法,以后就用ADC了
回復

使用道具 舉報

ID:401564 發表于 2022-9-26 17:12 | 顯示全部樓層
hhh402 發表于 2022-9-26 10:14
需要速度用STM32高主頻單片機。不過硬件不行靠軟件只能夠自己玩玩,電機能夠轉動而已,其他的就談不上了。
...

無刷電機不要什么高深的硬件呀,一般的就行,有入門的基礎就行
而且,TI早就有現成的硬件電路了,下載直接打開就行了
有AD格式的,打板就能用了
回復

使用道具 舉報

ID:195496 發表于 2022-9-28 13:07 | 顯示全部樓層
查表最快了,計算慢一點
回復

使用道具 舉報

ID:624769 發表于 2022-9-28 20:36 | 顯示全部樓層
Y_G_G 發表于 2022-9-26 17:10
不只是只要判斷有多少個1,還得判斷有多少個0,用來檢測IO從0變成1的一個點
或者是從1變成0
實際上就是上 ...

因為  b 就是 變量a 中1 的 個數。
所以,8-b  就是變量 a 中  0的個數。

之所以  建議你 if(IO) 的時候 就記錄 1/0 的個數,主要是為了 把時間 分攤到每次 檢測 IO 電平的時候。既 每次定時器中斷的時候 只需要 ++ -- 一次, 也就是 花費兩個 時鐘,當真正滿足你設定的條件時 是 1個時鐘 就出結果了, 真正做到最快響應。 反正,不管用什么方式去 判斷 a 里面有多少 1/0  就算用 查表,最少也要用 十幾個時鐘。當然你如果用匯編查表能快點,不過,你不是拋棄匯編了么?所以,也就不考慮了。

橫看豎看要在 a 里面的 1 的個數達到標準時,你最快的速度能夠知道滿足這個條件的話, 也就 b++; b-- ; 最合適了。
回復

使用道具 舉報

ID:401564 發表于 2022-9-28 21:53 | 顯示全部樓層
188610329 發表于 2022-9-28 20:36
因為  b 就是 變量a 中1 的 個數。
所以,8-b  就是變量 a 中  0的個數。

不是要看個數達到標準的
是要看什么時候出現從0變成1的真實時間點,這才是重點,我之前沒有描述清楚
用b++或者b--都會出現0x00和0xff的,因為無刷電機只有過零點才出現變化,其它時間,它會一直是0或者1
if(IO)
{
      a |= 0x01;
      b++;
}
在沒有到過零點的時候,假設IO一直是高電平,b就會有一個從255變成0的過程,低轉速的時候,換相時間是比較長的應該是會超過255*10uS=2,55mS
PIC那個方案,用新西達電機能跑1萬/分的轉速,因為電源沒有大于5A的,改天換個大電流的試一下能到多少
這個問題只是討論一下,以后肯定是要用ADC來計算的
回復

使用道具 舉報

ID:624769 發表于 2022-9-29 00:36 | 顯示全部樓層
Y_G_G 發表于 2022-9-28 21:53
不是要看個數達到標準的
是要看什么時候出現從0變成1的真實時間點,這才是重點,我之前沒有描述清楚
用b+ ...

我想,我在28樓的回復,你可能沒仔細看。或者,瀏覽器緩沖的關系,你這里沒有刷出來。我再貼一遍吧,

代碼如下:
a<<=1;
if(CY)   b--;
if(IO)
{
      a |= 0x01;
      b++;
}

你說的 255變0的問題是不會出現的, b永遠在 0~8 之間, 也永遠等于 a 里面 1的個數。
如果你長時間的 高電平, a= 0xff    那么b 也是 = 8, 你長時間的 低電平, a=0x00, 那么 b 也是 = 0; 這是完全同步的。 和你 把 a 拿去做任何算法 計算有多少1 是完全吻合的。

當然,我不是強迫你用這個方法, 只是我覺得可能 你沒完全理解  這個代碼的記錄原理,跟你再說明一下而已。
回復

使用道具 舉報

ID:86450 發表于 2022-10-22 17:02 | 顯示全部樓層
用 匯編 寫  ,不是更快嗎?
回復

使用道具 舉報

ID:624769 發表于 2022-10-22 23:08 來自手機 | 顯示全部樓層
jjwangxu2008 發表于 2022-10-22 17:02
用 匯編 寫  ,不是更快嗎?

你這問題說的……,人家好不容易拋棄了匯編,你讓人家吃回頭草?
回復

使用道具 舉報

ID:401564 發表于 2022-10-23 14:10 | 顯示全部樓層
jjwangxu2008 發表于 2022-10-22 17:02
用 匯編 寫  ,不是更快嗎?

我不知道是從什么地方傳出"匯編比C快"的說法的
網上說的匯編效率比C高,那得是匯編寫得好的
匯編寫得不好的,堆出來的代碼,效率要比C慢的
這個帖子討論了很多,我再說一次吧
我只想從多個抖動中快速的找到真實上升沿或者是下降沿,檢測BLDC無刷電機的過零點
論壇上,網上都有教程,但很多是低速的,高速的效果都不怎么好
回復

使用道具 舉報

ID:688692 發表于 2022-10-24 16:49 | 顯示全部樓層
樓主是需要多快的響應速度呢?還是這個響應速度是動態可變的?比如你采樣的速度是多少,出現多少個連續的0或者1就認為信號已經穩定了。
回復

使用道具 舉報

ID:401564 發表于 2022-10-24 17:54 | 顯示全部樓層
cnos 發表于 2022-10-24 16:49
樓主是需要多快的響應速度呢?還是這個響應速度是動態可變的?比如你采樣的速度是多少,出現多少個連續的0 ...

不是多少個0或者多少個1的問題
而是一個從0變成1,或者是從1變成0的真實時間
其實就是無刷電機過零檢測
10uS一次采樣,那么,檢測的過程也就1-2uS左右吧,時間太長,會影響到10uS的周期,而且,主程序還要一些時間呢
現在暫時是用ADC來檢測了,等到以后有時間了再改進一下這個程序
回復

使用道具 舉報

ID:639020 發表于 2022-10-24 18:52 | 顯示全部樓層
給你個參考代碼
  1. MOV R2,#8
  2.                         MOV R3,#0
  3.                 LOOP:RLC A
  4.                         JC $+4
  5.                         INC R3
  6.                         DJNZ R2,LOOP
  7.                         RET
復制代碼

最后R3返回的值大于16,就是1多于0
調用這個子程序一共花費54個指令周期,
如果你不用循環體,把代碼寫長一點,那么31個指令周期就夠了
回復

使用道具 舉報

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

本版積分規則

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

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 亚洲国产精品人人爽夜夜爽 | 99热这里都是精品 | 精品网 | 亚洲电影第1页 | 精品96久久久久久中文字幕无 | 国产精品欧美精品日韩精品 | 国产在线精品一区二区三区 | 久久国产精品视频免费看 | 成人中文字幕在线 | 精品久久99 | 91国产视频在线观看 | 中文字幕视频在线看5 | 欧美福利| 国产四区 | 日韩精品在线观看一区二区三区 | 欧美综合色 | 成人免费三级电影 | 成人精品福利 | 免费在线观看一区二区三区 | 国产成人在线视频播放 | 91中文字幕在线 | 精品91久久久 | 欧美精品三区 | 国产一级一级毛片 | 欧美一级二级三级视频 | 一区二区在线免费观看 | 国产原创视频 | 精品99在线 | 亚洲天堂中文字幕 | 日本不卡一区二区三区 | 午夜精品久久 | 秋霞在线一区 | 天天看片天天干 | 九九九久久国产免费 | 色就干| 97国产爽爽爽久久久 | 91视频麻豆 | 亚洲欧美日韩在线 | 日韩精品一区二区三区中文在线 | 免费视频二区 | 涩爱av一区二区三区 |