PIC初心者用掲示板

★★ 質問する前に下記をチェック ★★
(PICに関する疑問は必ず解決するはず)
←←←「電子工作の実験室」へ
←←←← 

■最新ツリー一覧

□このツリー付近のツリー一覧

★新規ツリー作成

◆ 9759. ROMの節約方法について [kita2006/02/25 22:13


9759. ROMの節約方法について [kita2006/02/25 22:13
A/D変換より得られたデータ変数(long型)を
float型に変換して、その変数によって条件分岐させるようなプログラムを書いていたら、あっというまにROM消費が100%近くになってしまいました。
まだ書きたいプログラムの半分もかけてないので
なんとかROMの消費を抑えたいのですが
どうすればROMの節約ができるのでしょうか?
今、ROMの消費が激しい原因はたぶん
上記で述べたような,AD変換後のデータを
float型に頻繁に変換しているからだと思うので
変数はグローバル変数になるようにすればいいと思いますが、プログラムがややこしくなるので
それはできればやりたくありません。

これについてのアドバイスをお願いします。
なお使用しているPICは16F877Aで、CCSのCコンパイラを使用しています。

9760. Re: ROMの節約方法について [kita2006/02/25 22:25
なお、プログラムは大体このような構成で、
これでコンパイル時にROM消費が96%と表示されます。

#include <16f877A.h>
#fuses HS,NOWDT,NOPROTECT,PUT,NOBROWNOUT,NOCPD,NOLVP
#device ADC=10//A/D変換10ビットモード
#use delay(CLOCK = 20000000)//クロック20MHz
#byte PORTB=6
#use fast_io(D)

////// 液晶表示器ライブラリ用設定
#byte PORTD = 8
#definePORT PORTD
#define set_tris_x set_tris_d
#define stb PIN_D2//制御信号設定
#define rs PIN_D0
#define rw PIN_D1//新しく付け加えた
#include <lcdlib3.c>//ライブラリインクルード

intcounter;//キースイッチ入力カウント用
longset_voltage, set_current;/// グローバル変数
float data;


//// 入力RB0割込み処理関数
#INT_EXT//RB0変化割り込み宣言

void ext_isr(void)
{
disable_interrupts(INT_TIMER0);//タイマー0変化割り込み禁止
disable_interrupts(INT_EXT);//RB0変化割り込み禁止
counter ++;
delay_ms(500);
}

//// タイマ0割込み処理関数
#INT_TIMER0//タイマ0割り込み宣言

void isr_t0(void)
{
/// 約300usec周期
set_timer0(0xe9);//タイマ0再設定、307.2us周期の割り込みになる
//// 計測実行
set_adc_channel(0);//チャネル0選択
delay_us(20);
set_voltage = read_adc();//電圧設定値入力

set_adc_channel(1);//チャネル1選択
delay_us(20);
set_current = read_adc();//電流設定値入力
}/////タイマー0の割り込み処理終了

9761. Re: ROMの節約方法について [kita2006/02/25 22:30
///// メイン関数
void main()
{
/// 入出力ポート設定
set_tris_a(0x0B);//AD変換用
set_tris_d(0);//全ピン出力モード
set_tris_b(0x01);//B0ピン入力モード、他は出力
port_b_pullups(TRUE);//ポートBプルアップON


counter=0;/// 初期クリア

/// A/D変換設定
setup_adc_ports(RA0_RA1_ANALOG_RA3_REF);//RA0,RA1ピンがアナログ入力
setup_adc(ADC_CLOCK_DIV_32);//Fosc/32 最高速度

/// タイマ0初期設定
setup_timer_0(RTCC_INTERNAL | RTCC_DIV_256);//プリスケーラ1/256 内部クロック
set_timer0(0xe9);

/// 初期クリア
set_voltage = 0;
set_current = 0;



//// 液晶表示初期表示
lcd_init();//液晶表示器初期化
lcd_clear();//全消去

printf(lcd_data, "Are you ready?");//今現在の電圧値にしますか?
delay_ms(2000);
lcd_clear();
printf(lcd_data,"Start!!");//スタートメッセージ出力
delay_ms(1000);
lcd_clear();//全消去

/// 割込み許可
enable_interrupts(INT_EXT);//RB0変化割り込み許可
enable_interrupts(GLOBAL);
ext_int_edge(H_TO_L);
/////////////////////////////////////////////


9762. Re: ROMの節約方法について [kita2006/02/25 22:32
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
while(1) //while1
{
if(counter==1)
{
while(1)
{disable_interrupts(INT_TIMER0);//タイマー0変化割り込み禁止
enable_interrupts(INT_EXT);//RB0変化割り込み許可
lcd_cmd(0x80);
printf(lcd_data, "OK?");//今現在の電圧値にしますか?
data = ((float)set_voltage*360 )/1024;//設定電圧変換
printf(lcd_data, "%03.0fV", data);//現在の設定電圧表示
if(counter==2){break;}
}//無限ループ終了
}//if,counter2終了

else
{
lcd_clear();
while(1)
{
enable_interrupts(INT_TIMER0);//タイマー0変化割り込み許可
lcd_cmd(0x80);
printf(lcd_data, "Set");
data = ((float)set_voltage*360 )/1024;//設定電圧変換
printf(lcd_data, "%03.0fV", data);//設定電圧表示
delay_ms(100);
if(counter==1){break;}
}//while終了
} //else終了
if(counter==2){break;}
}//while1終了

9763. Re: ROMの節約方法について [kita2006/02/25 23:02
if(counter==2)
{
disable_interrupts(INT_TIMER0);//タイマー0変化割り込み禁止
data = ((float)set_voltage*360 )/1024;//設定電圧変換
////////////////////////////////////////////////////////////////////////////////////////////
if(data>=0 && data<60)
{
while(1)
{
enable_interrupts(INT_EXT);//RB0変化割り込み許可
enable_interrupts(INT_TIMER0);//タイマー0変化割り込み許可
lcd_clear();
lcd_cmd(0x80);
printf(lcd_data, "first");
lcd_cmd(0xC0);//2行目の先頭へ移動
printf(lcd_data, "Set");
data = ((float)set_current*49 ) /10240;//設定電流変換
printf(lcd_data, "%01.1fA", data);//設定電流表示
delay_ms(100);
if(counter==3){break;}}//無限ループ終了

}
////////////////////////////////////////////////////////////////////////////////////////////
else if(data>=60 && data<160)
{
while(1)
{
enable_interrupts(INT_EXT);//RB0変化割り込み許可
enable_interrupts(INT_TIMER0);//タイマー0変化割り込み許可
lcd_clear();
lcd_cmd(0x80);
printf(lcd_data, "second");
lcd_cmd(0xC0);//2行目の先頭へ移動
printf(lcd_data, "Set");
data = ((float)set_current*25 ) /10240;//設定電流変換
printf(lcd_data, "%01.1fA", data);//設定電流表示
delay_ms(100);
if(counter==3){break;}}//無限ループ終了

}

9764. Re: ROMの節約方法について [kita2006/02/25 23:02
////////////////////////////////////////////////////////////////////////////////////////////
else if(data>=160 && data<=360)
{
while(1)
{
enable_interrupts(INT_EXT);//RB0変化割り込み許可
enable_interrupts(INT_TIMER0);//タイマー0変化割り込み許可
lcd_clear();
lcd_cmd(0x80);
printf(lcd_data, "third");
lcd_cmd(0xC0);//2行目の先頭へ移動
printf(lcd_data, "Set");
data = ((float)set_current*13 ) /10240;//設定電流変換
printf(lcd_data, "%01.1fA", data);//設定電流表示
delay_ms(100);
if(counter==3){break;}}//無限ループ終了

}
}//if,counter2終了
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
while(1)
{
lcd_clear();
lcd_cmd(0x80);
printf(lcd_data, "cleardesu");
delay_ms(100);
}
}> if(counter==2)
>{
>disable_interrupts(INT_TIMER0);//タイマー0変化割り込み禁止
>data = ((float)set_voltage*360 )/1024;//設定電圧変換
>////////////////////////////////////////////////////////////////////////////////////////////
>if(data>=0 && data<60)
>{
>while(1)
>{
>enable_interrupts(INT_EXT);//RB0変化割り込み許可
>enable_interrupts(INT_TIMER0);//タイマー0変化割り込み許可
>lcd_clear();
>lcd_cmd(0x80);
>printf(lcd_data, "first");
>lcd_cmd(0xC0);//2行目の先頭へ移動
>printf(lcd_data, "Set");
>data = ((float)set_current*49 ) /10240;//設定電流変換
>printf(lcd_data, "%01.1fA", data);//設定電流表示
>delay_ms(100);
>if(counter==3){break;}}//無限ループ終了
>
>}
>////////////////////////////////////////////////////////////////////////////////////////////
>else if(data>=60 && data<160)
>{
>while(1)
>{
>enable_interrupts(INT_EXT);//RB0変化割り込み許可
>enable_interrupts(INT_TIMER0);//タイマー0変化割り込み許可
>lcd_clear();
>lcd_cmd(0x80);
>printf(lcd_data, "second");
>lcd_cmd(0xC0);//2行目の先頭へ移動
>printf(lcd_data, "Set");
>data = ((float)set_current*25 ) /10240;//設定電流変換
>printf(lcd_data, "%01.1fA", data);//設定電流表示
>delay_ms(100);
>if(counter==3){break;}}//無限ループ終了
>
>}

9765. Re: ROMの節約方法について [kita2006/02/25 23:06
プログラムは9760から9674までです。
よろしくお願い致します。

9767. Re: ROMの節約方法について [初心者キング2006/02/25 23:34

使っているのはCCS-Cでしょ?だったら、
1. コンパイラの出力メッセージに、ROMの使用状況が出ているので、それを見る。
(どの出力結果かは、自分で調べて)
すでに100%になってコンパイル出来ないなら、何か削ってでも
コンパイラーを通す。
2. 16F877は
0x0000-0x07ff
0x0800-0x0fff
0x1000-0x17ff
0x1800-0x1fff
のつのROMバンクに分かれているので、4つのうちのどのバンクが
残りが多いかを調べる。
3. 関数の前に#ORG 0x1800 としてから、希望の関数を書く。
関数毎の指定なので、希望する関数の前にそれぞれ記述する。
#org 0x1800
void hoge(){
  処理....
}
こうすると、コンパイラ君は、hoge()をROMの0x1800-0x1fffに置いてくれる。
上記1から3を繰り返して、いろいろとやってみて、入る組み合わせを探す。
逆にROM位置を指定しまくると、入らない場合があるので、
小さいものは困憊ラムの自動配置に任せた方がよい場合もある。
#orgをしなければ自動配置の対象になる。

コンパイラー君は、関数を1つのバンクに入れようとする
(ていうか、バンクをまたぐことができない)ので、バンクサイズより
大きな関数は置けない。なので1本の大きな関数になっているなら、
出来る部分をさらに関数に出して、その関数を上記のように配置してみる。

特に大きくROMを消費する命令には、printf()やstr...の文字関数などが
ある。printf()について言えば、1文字や2文字しか出していないなら
putc()で複数回出力した方が、ROM消費は小さくなる。
よく使う、printf("\r\n");なども、putc(0x0d); putc(0x0a);とすれば
ROM消費をぐっと抑えられる。
float計算もROM消費が大きいので、可能なら整数で計算して
最後にfloatでキャストするなどの工夫をしてみるといい。

どう? できそう? 

9768. Re: ROMの節約方法について [PICマスター2006/02/25 23:36
>A/D変換より得られたデータ変数(long型)を
>float型に変換して、その変数によって条件分岐させるようなプログラムを書いていたら、あっというまにROM消費が100%近くになってしまいました。
>まだ書きたいプログラムの半分もかけてないので
>なんとかROMの消費を抑えたいのですが
>どうすればROMの節約ができるのでしょうか?
>今、ROMの消費が激しい原因はたぶん
>上記で述べたような,AD変換後のデータを
>float型に頻繁に変換しているからだと思うので
>変数はグローバル変数になるようにすればいいと思いますが、プログラムがややこしくなるので
>それはできればやりたくありません。
>
>これについてのアドバイスをお願いします。
>なお使用しているPICは16F877Aで、CCSのCコンパイラを使用しています。

プログラムをどかどかと書かれてもデバッグするほどにはヒマじゃないので、思うところを・・・。

>変数はグローバル変数になるようにすればいいと思いますが、プログラムがややこしくなるのでそれはできればやりたくありません。

「ややこしくなる」のはなく、「ややこしくしてる」んです。プログラムをきっちりと追い込んで作れば問題ないかと思います。

きめ細かなサブルーチン化、CCS-Cで出来るのかどうか知りませんが、インラインアセンブラ使うとか。

そもそもやろうとしていることと、デバイス(この場合はPIC)とが合ってないのでは?。もっとエリアの広いデバイスを使うか、思い切ってアセンブラでスリムにシェイプアップするか・・・。

ちなみに同じようなことをしたことがありますが、アセンブラなのでおよそ40%程度のサイズでできました。

まぁ、アドバイスとしては「手間を惜しんじゃいけません」ってトコロです。

9769. Re: ROMの節約方法について [初心者キング2006/02/25 23:59
>プログラムは9760から9674までです。
なんだか、わかりにくいプログラムだな。
途中まで整形していったけど、やめた。

外部割り込み毎に処理が変わって
AD結果によって、処理が分かれているようだが、
似たような処理ばっかじゃん。
見ててイライラしちゃった。

 組み直し!!

 組み直せばROM容量はガンガン落とせる。
 健闘を祈る。

9773. Re: ROMの節約方法について [kita2006/02/26 17:58
アドバイスありがとうございます。
とりあえず今日は
float計算を整数で計算することと、
printf()をputc()で書き直すということを考えていたのですが、両方ともうまく理解できないでもう夕方に
なってしまいました。

まずfloat計算のほうですが、
最初にdataとset_voltageをlong型で宣言していて、
data = (set_voltage*360/1024);
とすることで0~360の数値を得たいのですが、
LCDに表示されるデータがそうなりません。
longで宣言している変数は、10進数として計算できないのでしょうか?

次にprintfとputcのことなのですが、
putcはどのように使用すればよいのでしょうか?
CCSの日本語マニュアルを読んでもさっぱり意味が
理解できません。

度々申し訳ありませんが、
このことについてのアドバイスをお願い致します。

9774. Re: ROMの節約方法について [   2006/02/26 21:46

>まずfloat計算のほうですが、
>最初にdataとset_voltageをlong型で宣言していて、
> data = (set_voltage*360/1024);
>とすることで0~360の数値を得たいのですが、
>LCDに表示されるデータがそうなりません。

data = (set_voltage*45/128);
と変形すればいいと思うよ。

9775. Re: ROMの節約方法について [kita2006/02/26 22:28
> data = (set_voltage*45/128);
>と変形すればいいと思うよ。
すみません、45、128というのは
どのように考えると出てくる数字なのでしょうか?

9776. Re: ROMの節約方法について [kita2006/02/26 22:35
コンパイル時にROMが100%を超えると注意された時に
コンパイルの画面には
main
Seg 00037-007FF, 041C left, need 046D
0000
Seg 00000-00003, 0000 left, need 046D
0000
Seg 00004-00036, 0000 left, need 046D
0000
と表示されていました。
これがROMの使用状況を表しているのでしょうか?
どういった意味なのでしょうか?
この件についてもよろしくお願い致します。

9777. Re: ROMの節約方法について [初心者キング2006/02/26 23:49

>まぁ、アドバイスとしては「手間を惜しんじゃいけません」ってトコロです。

いいこと言うなあ。なんか身に染みる。涙出てきた。

9778. Re: ROMの節約方法について [   2006/02/27 00:00
>> data = (set_voltage*45/128);
>>と変形すればいいと思うよ。
>すみません、45、128というのは
>どのように考えると出てくる数字なのでしょうか?

360/1024 = 45/128
簡単な分数の計算ですがわかりませんか?

ちなみにCCSCでlongは0〜65535の範囲です。
1024で割って360になる数は368640ですから、桁あふれしています。
128で割って360になる数は46080なのでok。

9779. Re: ROMの節約方法について [怒髪上衝冠2006/02/27 00:05
>> data = (set_voltage*45/128);
>>と変形すればいいと思うよ。
>すみません、45、128というのは
>どのように考えると出てくる数字なのでしょうか?
>

算数をもう一度勉強し直したら?
分子分母を8で割れば、出てくるんじゃないの!
約分って勉強しませんでしか?
それからADは10bitですが、AD変換結果の最大値は
1023。
ということはdata = (set_voltage*45/128);という
計算式では360は決して表示されないと思いますが・・・
もちろんdata = (set_voltage*360/1024);でも同じ!
本にもこういった計算が掲載されていますが、チョット
違うような気がします、どうでしょうか?

9780. Re: ROMの節約方法について [kita2006/02/27 00:33
>ちなみにCCSCでlongは0〜65535の範囲です。
>1024で割って360になる数は368640ですから、桁あふれしています。
>128で割って360になる数は46080なのでok。
>
なるほど!分かりました。ありがとうございます。

9784. Re: ROMの節約方法について [PICマスター2006/02/27 12:46
>いいこと言うなあ。なんか身に染みる。涙出てきた。
「手間を惜しむな」は、初心者であろうとベテランであろうと忘れてはならない事なのだと肝に銘じています。仕事柄機密に関わるため、自身のサイトを作ることが出来ないのですが、教える側の立場でもあるのでこういうトコロにしゃしゃり出てきました(^^;。

PICを使うことを取ってみても、ここのHPもそうですし他の様々なサイトもしっかりと見て、公開されている作例等を「正しく」盗めば、ステップアップ出来ることは確実です。またデータシートも、邦訳されているものはきちんと読み、英文のみのモノも辞書片手に訳していけば、そのうちに読めるようになります。