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

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 4726|回復: 20
收起左側

請問單片機的浮點的運算要怎么處理?

[復制鏈接]
ID:961122 發表于 2021-9-5 13:23 | 顯示全部樓層 |閱讀模式
請問exp()函數輸入輸出都是浮點數,計算的最終結果要一個整數。
請問要始何做才能得到正確的結果。下面的程序一得出的數值不正確。
公式在下圖。
#include <math.h>
#defind  FOSC/2/11059200
unsigned int Int_value;
unsigned int Int_i;
for((Int_i=0; Int_i < 1000; Int_i++)
{
Int_value=(unsigned int)(1600+(5304-1600)/(1+(exp(-5*(Int_i-500)/500)))
}

20160817141658638.jpg
回復

使用道具 舉報

ID:161164 發表于 2021-9-5 16:50 | 顯示全部樓層
Int_i的類型是無符號
Int_i-500這一步會等于65536-500=65036

應改作
Int_value=(unsigned int)(1600+(5304-1600)/(1+(exp(-5*(((float)Int_i-500)/500)))));
回復

使用道具 舉報

ID:624769 發表于 2021-9-5 17:22 | 顯示全部樓層
首先, 你要浮點運算的話,變量類型不能用INT
必須要用 float,其次盡可能所有參與浮點運算的變量最好都是 float
最后,不知道你的單片機什么內核的,如果是51內核,最好避免浮點運算。是真的抗不住。不管是最后編譯后的代碼量,還是對MCU的負荷都是巨大的。
回復

使用道具 舉報

ID:961122 發表于 2021-9-5 18:53 | 顯示全部樓層
按兩位指導改了一下測試程序,數值對了。也確實運算時間太長了。
#include <reg51.h>
#include <math.h>

#define FOSC 11059200L
void main(void)
{
unsigned int ;
float Int_i,scale,fmin,fmax,node;
float Int_value;
float b;

P10=1;
Int_i=1;
fmin=1600;
fmax=5304;
scale=4;
node=1000;

b= exp((-scale*(Int_i-node/2)/(node/2)));
Int_value= (unsigned int)(FOSC/2/(fmin+(fmax-fmin)/(1+b)));       
//if (b>54 && b<55)
if (Int_value=3316)
P10=0;
else
P10=1;

while(1);
}
回復

使用道具 舉報

ID:624769 發表于 2021-9-5 21:16 | 顯示全部樓層
litingkun 發表于 2021-9-5 18:53
按兩位指導改了一下測試程序,數值對了。也確實運算時間太長了。
#include
#include

如果,能用 1K以內的 查表來代替的話,能不用浮點就不用浮點吧。
回復

使用道具 舉報

ID:57657 發表于 2021-9-5 21:43 | 顯示全部樓層
litingkun 發表于 2021-9-5 18:53
按兩位指導改了一下測試程序,數值對了。也確實運算時間太長了。
#include
#include

8位單片機,浮點運算性能較差,具體需要多長時間需要用邏輯分析儀檢測。
回復

使用道具 舉報

ID:624769 發表于 2021-9-5 21:49 | 顯示全部樓層
npn 發表于 2021-9-5 21:43
8位單片機,浮點運算性能較差,具體需要多長時間需要用邏輯分析儀檢測。

51內核的話,壓根不是差的問題了……,是根本沒有浮點運算能力,是用海量的整形來模擬浮點運算。所以,根本抗不住,用這種模擬浮點,把單片機做個計算器也就算了,做其他的東西,壓根等不起。
回復

使用道具 舉報

ID:961122 發表于 2021-9-5 21:51 | 顯示全部樓層
調了兩天最后數值調對了,從1600Hz加速到5304H,中間1000個脈沖,估計是0.26S 終果電機一抖一抖用了大概3S才加速完。
回復

使用道具 舉報

ID:961122 發表于 2021-9-5 21:52 | 顯示全部樓層
單片機STC15W408AS
回復

使用道具 舉報

ID:883242 發表于 2021-9-5 23:34 | 顯示全部樓層
應該用PC上面的c語言編譯器按照你的公式生成一個表格,比你現在的代碼不僅快還省Flash空間。
回復

使用道具 舉報

ID:401564 發表于 2021-9-5 23:43 | 顯示全部樓層
litingkun 發表于 2021-9-5 21:51
調了兩天最后數值調對了,從1600Hz加速到5304H,中間1000個脈沖,估計是0.26S 終果電機一抖一抖用了 ...

時間長并不是浮點數的問題
8位單片機在浮點運算上的能力是比較弱的,速度會很慢,用時相當的長
但這是對于CPU"時間"而言的,并不是針對現實的時間
你這個用時那么長,難不成是一直在計算?就是換了整型運算,也是一樣的

(double)(GPS_Buffer1.GPS_Buffer[a+4]-48)/1000+(double)(GPS_Buffer1.GPS_Buffer[a+5]-48)/10000
   )/60;
8051進行以上運算用了367個字節長度的代碼進行,指令用了200條左右,12M晶振以1T的STC8051單片機運算,用時就是:200*1/12,大概就是16uS,往大了說,就是1mS也不算長呀
回復

使用道具 舉報

ID:961122 發表于 2021-9-6 00:20 | 顯示全部樓層
Y_G_G 發表于 2021-9-5 23:43
時間長并不是浮點數的問題
8位單片機在浮點運算上的能力是比較弱的,速度會很慢,用時相當的長
但這是對 ...

我用在脈沖輸出,運算寫在中斷里,每個脈沖改一次頻率,設了一個燈,如果加速完成,燈就亮。燈亮的時間大概是3秒。
void PCA_isr() interrupt 7
{

if ((unsigned int)Int_i < (unsigned int)Pnode )                                                                //脈沖數量小于node數量 加速運行
{
CCF0 = 0;                                                                                //清除中斷標示位

CCAP0L = Int_value;
CCAP0H = Int_value>> 8;


Int_value+= (signed int)(FOSC/2/FREQDIV/(Pmin+(Pmax-Pmin)/(1+exp(-Pscale*(Int_i-Pnode/2)/(Pnode/2)))));

Int_i++;
}
else                                                                                        //最高脈沖勻速運行
{
CCF0 = 0;                                                                                //清除中斷標示位

CCAP0L = Int_value;
CCAP0H = Int_value>> 8;

Int_value+=        (signed int)(FOSC/2/FREQDIV/Pmax);

}
}
回復

使用道具 舉報

ID:401564 發表于 2021-9-6 06:16 | 顯示全部樓層
litingkun 發表于 2021-9-6 00:20
我用在脈沖輸出,運算寫在中斷里,每個脈沖改一次頻率,設了一個燈,如果加速完成,燈就亮。燈亮的時間大 ...

看不到完整的程序,不知道怎么回事
沒有看到PCA相關設定,PCA工作在什么模式?
回復

使用道具 舉報

ID:961122 發表于 2021-9-6 08:09 | 顯示全部樓層
Y_G_G 發表于 2021-9-6 06:16
看不到完整的程序,不知道怎么回事
沒有看到PCA相關設定,PCA工作在什么模式?

PCA 高速脈沖輸出,系統時鐘11059200 不分頻。
CCON = 0x00;
CMOD = 0x08;                                //PCA時鐘為系統時鐘
CL = 0x00;
CH = 0x00;
CCAPM0 = 0x4d;                              //PCA模塊0為16位定時器模式并使能脈沖輸出
回復

使用道具 舉報

ID:401564 發表于 2021-9-6 09:23 | 顯示全部樓層
litingkun 發表于 2021-9-6 08:09
PCA 高速脈沖輸出,系統時鐘11059200 不分頻。
CCON = 0x00;
CMOD = 0x08;                            ...

我也是服了,在我遇到的絕大多數人中,用到STC的,一般就是DIY或者學習,所以,我并不覺得一個一個STC的代碼有什么保密性可言,你就不能上傳一個完整的工程文件?到這問問題,你就應該先考慮到這個要不要保密的問題了

暫時不說這個,就你的程序而言
if (Int_value=3316)    你不得少了一個"="嗎?
Int_i在大于Pnode之后是怎么處理的?
我可以認為,你說的3秒,問題肯定不是出現在"浮點數"上,單片機在浮點運算上是很"弱",但并不是絕對的不能用
回復

使用道具 舉報

ID:961122 發表于 2021-9-6 18:37 | 顯示全部樓層
    先感謝各位前輩指導,這個論壇的人真的很熱心。
因只是自學,非商用,程序也沒保密一說,只是全貼太多,怕耐心無法支持看完。所以只寫了重點。
    附件是程序,用PCA的高速脈沖輸出控制步進電機(配控制器的),電機加速啟動。加速的參數和方程上文已提到。方程寫在脈沖中斷里面,中斷時計數器賦新值,方程計算下一個值。加速完成LED燈亮起。
    但實現運行起來電機咔咔的響。燈亮的時間實際是8s.所以應該是每個脈沖都做浮點運算,運算時間比脈沖發送本身都長導致的。
    還想請教各位前輩,有什么辦法實現脈沖頻率按方程變化。如果寫一個表在EEPROM里面,想通過按鍵改變加啟變化就不容易了。
//S曲線脈沖輸出C文件
//21-9-2 V1.0
//作者:Tony
//說明:SYSclk=11059200 FOSC=SYSclk 模塊0
//        node節點數量大65536


#include "pulse.h"                                                                                                                                   //!!注意點,一定要引入!!


WORD Int_value;
float Int_i,Pmin,Pmax,Pnode,Pscale;                                                                                            //全局變量
/*****************************************************************************

** 函數名稱: PCA_isr()

** 功能描述: PCA脈沖中斷

** 全局變量: Int_i ; Pnode ; Int_value ;Pmin;Pmax;Pscale;Pnode

** 調用模塊: 無

** 輸入: 無

** 輸出: 無

******************************************************************************/
void PCA_isr() interrupt 7
{

if ((unsigned int)Int_i < (unsigned int)Pnode )                                                                //脈沖數量小于node數量 加速運行
{
CCF0 = 0;                                                                                //清除中斷標示位

CCAP0L = Int_value;
CCAP0H = Int_value>> 8;


Int_value+= (signed int)(FOSC/2/FREQDIV/(Pmin+(Pmax-Pmin)/(1+exp(-Pscale*(Int_i-Pnode/2)/(Pnode/2)))));

Int_i++;
}
else                                                                                        //最高脈沖勻速運行
{
CCF0 = 0;                                                                                //清除中斷標示位

CCAP0L = Int_value;
CCAP0H = Int_value>> 8;

Int_value+=        (signed int)(FOSC/2/FREQDIV/Pmax);
P10=0;
}
}


/*****************************************************************************

** 函數名稱: ACCStart

** 功能描述: 加速啟動函數

** 全局變量: 無

** 調用模塊: main()

** 輸入: fmin:啟動脈沖頻率,fmax:最高脈沖頻率,scale:加速系統,node:脈沖數量

** 輸出: 無

******************************************************************************/
void ACCStart(WORD fmin ,WORD fmax, BYTE scale, WORD node)
{


Int_value=0;                                                            //初始化脈沖數

if(CR == 1)                                                                        //啟動判斷         CR=1退出程序
return;

CCON = 0x00;                                                                //初始化PCA控制寄存器          PCA定時器停止         清除CF標志         清除模塊中斷標志                                   
CMOD = 0x08;                                //PCA時鐘為系統時鐘         禁止寄存器CCON中CF位的中斷
CL = 0x00;                                                                        //復位PCA寄存器
CH = 0x00;
CCAPM0 = 0x4d;                              //PCA模塊0為16位定時器模式并使能脈沖輸出                                                                               
                                                                               
Pmin=fmin;
Pmax=fmax;
Pscale=scale;
Pnode=node;

Int_value=FOSC/2/FREQDIV/Pmin;                                                                        //初始脈沖數賦值                                                                
CCAP0L = Int_value;                                                 
CCAP0H = Int_value >> 8;

Int_value+= (signed int)(FOSC/2/FREQDIV/(Pmin+(Pmax-Pmin)/(1+exp(-Pscale*(1-Pnode/2)/(Pnode/2)))));                  //第2個脈沖數計算
               
Int_i=2;
CR = 1;                                                                                                                                     //啟動PCA計時器
EA = 1;                                                                                                                                                                          //啟動中斷使能                                                                                       
}

回復

使用道具 舉報

ID:624769 發表于 2021-9-6 19:06 | 顯示全部樓層
litingkun 發表于 2021-9-6 18:37
先感謝各位前輩指導,這個論壇的人真的很熱心。
因只是自學,非商用,程序也沒保密一說,只是全貼太多 ...

你問題如果解決了,就不用再貼代碼上來了.
運算時間長,是在我意料之中的。
也許有人覺得,浮點運算,對于沒有硬件浮點運算器的51單片機沒什么影響。但是,實際上影響還是很大的。
如果純粹的 浮點數的加減乘除,還好一點。但是你的程序里用到了  EXP, 我沒記錯的話,EXP 是 MATH.H 函數庫里的東西。 但凡用到了 MATH.H 我就沒舒服過。有一次寫代碼用到 LOG, 直接把我弄得沒脾氣了。所以我才提議,能搞出一個 數據表的話, 用查表會好點。后來但凡遇到需要用MATH.H 的 我都盡量的改成查表。順便提一下,KEIL 自帶的函數庫,都是比較傻的,如果有能力自己寫幾個函數庫,會效率更高。舉個簡單例子,你LONG型除以一個CHAR 型,KEIL 的做法是把你的CHAR 型也變成 LONG,然后用加法器的SUBB 來移位減法來做除法,效率之低令人發指,自己寫一個函數分段用DIV,效率能提升30倍。

所以,你要優化你的代碼的話……
可以考慮把你的那段公式拆分。能在 CHAR 或者 Short ,LONG完成的部分,先完成。最后再去進行浮點運算,浮點運算后如果后續可以不用浮點了,盡快轉成整形,那么,單片機的效率又可以一個提升。
有些死的東西可以提前算好,放到臨時變量。比如 FOSC/2/FREQDIV  你不用每次都算吧?可以先算好,來減輕浮點運算時的負擔。
回復

使用道具 舉報

ID:401564 發表于 2021-9-6 23:13 | 顯示全部樓層
litingkun 發表于 2021-9-6 18:37
先感謝各位前輩指導,這個論壇的人真的很熱心。
因只是自學,非商用,程序也沒保密一說,只是全貼太多 ...

你確定主函數中這個if (Int_value=3316)不改一下嗎?
回復

使用道具 舉報

ID:883242 發表于 2021-9-7 05:07 | 顯示全部樓層
  1. int32_t fxexp(int32_t x) {
  2.         int32_t t,y;

  3.         y=0x00010000;
  4.         t=x-0x58b91;if(t>=0) x=t,y<<=8;
  5.         t=x-0x2c5c8;if(t>=0) x=t,y<<=4;
  6.         t=x-0x162e4;if(t>=0) x=t,y<<=2;
  7.         t=x-0x0b172;if(t>=0) x=t,y<<=1;
  8.         t=x-0x067cd;if(t>=0) x=t,y+=y>>1;
  9.         t=x-0x03920;if(t>=0) x=t,y+=y>>2;
  10.         t=x-0x01e27;if(t>=0) x=t,y+=y>>3;
  11.         t=x-0x00f85;if(t>=0) x=t,y+=y>>4;
  12.         t=x-0x007e1;if(t>=0) x=t,y+=y>>5;
  13.         t=x-0x003f8;if(t>=0) x=t,y+=y>>6;
  14.         t=x-0x001fe;if(t>=0) x=t,y+=y>>7;
  15.         if(x&0x100)               y+=y>>8;
  16.         if(x&0x080)               y+=y>>9;
  17.         if(x&0x040)               y+=y>>10;
  18.         if(x&0x020)               y+=y>>11;
  19.         if(x&0x010)               y+=y>>12;
  20.         if(x&0x008)               y+=y>>13;
  21.         if(x&0x004)               y+=y>>14;
  22.         if(x&0x002)               y+=y>>15;
  23.         if(x&0x001)               y+=y>>16;
  24.         return y;
  25. }
復制代碼

給你貼個定點數exp()算法吧,32位,小數點在16位,也就是說0x10000表示1,0x7fffffff表示32768。函數的入口和出口都是這種定點格式。
回復

使用道具 舉報

ID:213173 發表于 2021-9-7 08:35 | 顯示全部樓層
litingkun 發表于 2021-9-6 18:37
先感謝各位前輩指導,這個論壇的人真的很熱心。
因只是自學,非商用,程序也沒保密一說,只是全貼太多 ...

樓主這個程序的計算方式耗時遠大于脈沖周期,怎么可能正常運行?完全相同的數據重復計算為什么不放在預處理完成?只不過算PCA定時器初值不至要用浮點運算。可以借鑒如下連接中本人回帖的思路處理PCA定時器初值。
http://www.zg4o1577.cn/bbs/forum.php?mod=viewthread&tid=211892
利用Excel工作表SUM函數功能,計算脈沖周期制作一個16位數組,直接調用數組賦值。

CCAP0L = Int_v;
CCAP0H = Int_v >> 8;
i++;




回復

使用道具 舉報

ID:961122 發表于 2021-9-8 11:59 | 顯示全部樓層
Hephaestus 發表于 2021-9-7 05:07
給你貼個定點數exp()算法吧,32位,小數點在16位,也就是說0x10000表示1,0x7fffffff表示32768。函數的入 ...

回復

使用道具 舉報

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

本版積分規則

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

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 日韩久久久久久 | 日日综合| 欧美激情五月 | 亚洲小视频在线观看 | 鸡毛片| 福利片在线观看 | 日本视频一区二区 | 天天玩天天干天天操 | 91国产精品| 九色在线观看 | 1000部精品久久久久久久久 | 久久久av | 国产精品国产精品国产专区不片 | 日韩在线不卡视频 | 亚洲精品视频一区 | 81精品国产乱码久久久久久 | 毛片一区二区三区 | www.887色视频免费 | 国产1区2区3区 | 精品中文字幕一区二区三区 | 国产中文字幕亚洲 | 中文字幕免费 | 精品美女视频在免费观看 | 91观看| 最新免费黄色网址 | 午夜精品久久久久99蜜 | 久久噜噜噜精品国产亚洲综合 | 一区二区三区视频在线观看 | 久久黄视频| 九九久久精品视频 | 国产精品区二区三区日本 | 日本久久www成人免 成人久久久久 | 成人国产精品色哟哟 | 国产资源网 | 国产影音先锋 | 精品一区二区电影 | 久久精品色欧美aⅴ一区二区 | 国产一区二区三区视频 | 四虎午夜剧场 | 日韩免费一区二区 | 91国在线|