#define F_CPU という設定の意味と内部周波数の影響

このQ&Aのポイント
  • この質問は、Atmel Studio6.1 + JTAGICE3でATmega88Pのプログラミングを行っている中で、リアルタイムデバッグ中に発生した問題に関するものです。
  • #define F_CPUは、プログラム内で使用されるクロック周波数を指定するマクロ定義です。内部周波数の変更によって、CC1101とのSPI通信やeepromへのデータ書き込みに影響が生じることがあります。
  • 元周波数が8MHzの場合、8CKDIVのチェックを外すことで内部周波数が8MHzに設定され、コードに到達できます。一方、4分周した2MHzの場合、CC1101とのSPI通信ができなくなります。2000000ULという値は、内部周波数を2MHzに設定するためのものですが、この考えで正しいです。
回答を見る
  • ベストアンサー

#define F_CPU という設定

現在Atmel Studio6.1 + JTAGICE3でATmega88Pのプログラミングを行っています。 https://sourceforge.jp/projects/cc1101driver/scm/svn/tree/head/branches/test002_AVRS6_20140819/test02/ このプロジェクト内で、リアルタイムデバッグを行っているソースコードで、無線モジュールIC CC1101がある端末出力されて受信したデータがあった場合、SPI通信でATmega88PマイコンにSPI通信割り込みでデータを送信して、データ内容で条件が適合するとAtmega88pの特定のeepromアドレスへ受信データ内容の一部データ(IDコード)を書き込むようにしている箇所があります。 u8 setup_oper() 関数内の length = cc1101_rx((u8 *)fifo,0); if(length > 0) { gggLength = length; if(length == sizeof(fifo_t) && fifo-                        ・・・・(中略)・・・・ } リアルタイムデバッグ中に上記のコードで端末側がデータ送信を行っているのに、受信した場合にlength = cc1101_rx((u8 *)fifo,0); のコード部分では受信したデータのlength値が代入されるはずなのですが、それが”0”のままであるため、eepromへの書き込みが行われていないことに気づきました。 いろいろとソースコードの修正を試みたところ、 #define F_CPU 800000UL 元々このように設定されていたコードを #define F_CPU 2000000UL このように変更したところ、正常にCC1101からのSPI通信もeepromへのデータ書き込みもうまくいくことがわかりました。 この”#define F_CPU”というコードはどのような意味があるのかご教示頂きますよう、よろしくお願い致します。 また、現在Atmega88pの元周波数は8MHzを使用したく、8CKDIVのチェックを外しています。 なので、 #define F_CPU 8000000UL このように設定してみたところ、これだとCC1101とのSPI通信ができないようでeeprom書き込みのコードに到達できなくなります。 #define F_CPU 2000000UL これは内部周波数が元の8MHzを4分周した2MHzのことなのだろうか? このように思って2000000ULとしてみたのですが、この考えでよろしいのでしょうか? どうぞ、ご教示頂き増増すよう、よろしくお願い致します。

質問者が選んだベストアンサー

  • ベストアンサー
  • black2005
  • ベストアンサー率32% (1968/6046)
回答No.1

>#define F_CPU 2000000UL マクロ定数と言い、関数内で”F_CPU”と記述すれば、コンパイル時に2000000という数字に置換されます。 複数回F_CPUを使っていても、#define行の数値だけを変更してリコンパイルすれば、全てのF_CPUが一括変更されるので非常に便利です。 例えば clock_A = F_CPU/4 ; と記述してコンパイルすれば clock_A = 2000000/4 ; と置換され、clock_Aが求められます。 後半の質問はソースコードの解析が必要なので、さすがに回答出来ません。

techhouse
質問者

お礼

回答頂きありがとうございます。助かります。

その他の回答 (2)

  • kabasan
  • ベストアンサー率44% (264/588)
回答No.3

検索すればすぐわかることですが、F_CPUはシステムクロック周波数の定数宣言ですね。 ですから8MHzで使うなら  #define F_CPU 8000000UL  が正解です。 なぜ意図した動作をしないかですが、まず警告メッセージのないソースにしなければデバッグどころではありませんよ。 cc1100.cやi2c.cではF_CPUが宣言されていないので、デフォルトの10MHzとしてコンパイルされています。 まあ、_delay_msの精度がでないだけなのでたいした問題ではないでしょうが・・・・ あと、関数プロトタイプ宣言もちゃんと書きましょう。

techhouse
質問者

お礼

回答頂きありがとうございます。今までAVR Studio4 + winAVRでのプログラムではF_CPUというのは無かったように思うのですが、Atmel Studio5からはこのような定義が必要になったということを確認しました。 今まではマイコンの内部クリスタルの周波数を使う場合はヒューズビットの設定で内部周波数が決定されると思っていました。

  • black2005
  • ベストアンサー率32% (1968/6046)
回答No.2

No.1です。 回答はしたものの・・・ まさか#defineの意味も解らずに、Cソースを読んだり書いたりする人はいないよな? と考えたら、回答が的外れのような気がしてきました。 だとしたら、ゴメンなさい。

techhouse
質問者

お礼

回答頂きありがとうございます。#defineというのを使ったことが無いわけではないのですが、AVR Studio4 + winAVRでのプログラミングの時には、#define F_CPU 2000000ULこのようなマクロ定義のコードを書いたことが無かったので、今度からは必要なのかなと感じております。

関連するQ&A

  • Atmel Studioのeepromアドレス

    現在Atmel Studio6.2でATmega88pマイコンのプログラミングを行っています。 https://sourceforge.jp/projects/cc1101driver/scm/svn/blobs/head/branches/test002_AVRS6_20140819/test02/test02/src/main.c AVR studio4.19 + winAVR Cコンパイラで作成していたコードをAtmel Studio6.2に移してコンパイルを行ったところ、EEPROMアドレスへのデータ書き込みが逆になってしまう現象が起きました。 #define EEPROM __attribute__((section(".eeprom"))) ctl_data EEPROM gctl_data; reg_slave EEPROM greg_slave[100]; int EEPROM eprom_level[14]; char EEPROM eprom_fixid[3]; char EEPROM test_mode; char EEPROM monitor_state; int EEPROM wdt_cnt; int EEPROM cnt_loop_break; このようなコードを”AVR studio4.19 + winAVR”の時からしているのですが、このときは ctl_data EEPROM gctl_data; こちらがEEPROMアドレスの0x0000番地から始まっていたのですが、Atmel Studio6.2の場合は、 int EEPROM cnt_loop_break; こちら側が0x0000番地に配置するようになっていて、逆になってしまっています。 この場合、一番最初のアドレスに割り当てするには、コードも逆にして記述する必要がありますでしょうか? どうぞ、ご教示頂きますようお願いいたします。

  • SPI通信制御付きの音声ICをI2Cで制御可能?

    SPI通信のRX端子搭載で、音声の再生や停止などを制御できる音声ICをATMELのAtmega88Pというマイコンで行おうと思っているのですが、Atmega88PにはSPI機能の端子が1つだけで、デバッガの接続のみに専念させたいと考えています。 一応、空いている端子があるので、プログラムで擬似的にSPI通信の作ってそれで制御することを考えているのですが、Atmega88PのI2C端子も空いているのですが、これをSPIの送信のみに特化したような使い方はできますでしょうか? 確か、I2CはACKのビットが入ってきて、単純に1バイトを8ビットで送信するという感じではダメだったような気がするのですが、可能でしょうか? どうぞ、ご教示頂きますよう宜しくお願い致します。

  • PIC16F1823 SPI通信

    PIC16F1823をマスターとして、スレーブデバイスから、SPI通信にてデータを読み込もうとしています。オシロスコープで波形を見ると、期待したデータをスレーブ側は出力しています。しかし、PICでは、0x00のデータしか受信されません。 PIC側のマスター受信では、SSP1BUFをダミーで読み込み、SPIでコマンドを送信、SSP1BUF.BFをみて、さらにSSP1BUFをダミーで読み込み、次にデータ受信用にダミーデータと受信を行い、SSP1BUF.BFをみて、SSP1BUFを読んでいます。気を付けて確認しなけらばならないレジスタ等あったら教えてください。

  • EEPROMからRAMへ移動したがウォッチできない

    現在、Atmel Studio6.2でatmega88pマイコンのプログラミングを行っています。リアルタイムデバッグではJTAGICE3を使用しています。プログラムのVersion値とeepromに保存しているVersion値を比較して、違いがあった場合は、プログラムの更新があったことを記録するため、最新のVersion値をEEPROMに書き込むプログラムを作成したのですが、EEPROMからRAM領域へ取り出したデータをリアルタイムデバッグでウォッチできない現象が起こり困っています。 なお、このプロジェクトフォルダは https://sourceforge.jp/projects/cc1101driver/scm/svn/tree/2564/branches/test002_AVRS6_20140819/test02/ こちらで公開させてもらっています。 (EEPROM領域側) #define EEPROM __attribute__((section(".eeprom"))) save_eeprom_data_t EEPROM save_eeprom_data; (RAM領域側) new_ctl_data tnew_ctl_data; main関数スタート後 check_env()関数内でEEPROM領域からRAM領域へデータを my_eeprom_read_block((u8 *)&tnew_ctl_data,(u8 *)&save_eeprom_data.gnew_ctl_data,sizeof(ctl_data)); この関数で読み出しているのですが、再度main関数内で if(tnew_ctl_data.fix_osccal_flag != 0x01 || tnew_ctl_data.prog_ver != PRG_VERSION) { ------(中略)--------------------------------- } このコードに来たときにtnew_ctl_dataをウォッチしても new_ctl_data.fix_osccal_flag tnew_ctl_data.prog_ver どちらの値も0x00と表示されてしまいます。 また、 tnew_ctl_data.prog_ver の値は0xdcのはずなのですが、0x00となっており、 PRG_VERSIONは #define PRG_VERSION 0xDD 0x00 と0xDDでは違いが出ているのですが、そのときの条件でEEPROM内容を tnew_ctl_data.fix_osccal_flag = 0x01; tnew_ctl_data.prog_ver = PRG_VERSION; eeprom_busy_wait(); eeprom_write_block(&tnew_ctl_data.fix_osccal_val,&save_eeprom_data.gnew_ctl_data.fix_osccal_val,3); このコードで0xddにtnew_ctl_data.prog_verの領域バイトを書き換えるはずなのですが、0xdcのままになってしまいます。 このような場合、どのように修正したら良いのかをご教示頂きますよう、お願い致します。

  • FOMA P2402とFOMA F2402について

    インターネットをしたいと思いドコモのCFカードタイプを使用したいと思っていますが、FOMA P2402とFOMA F2402について質問があります。FOMA P2402の説明に受信最大384kbpsの高速パケット通信と大容量データの送受信に適した64Kデータ通信の2つの通信方式に対応とあるのですが、パケット通信とデータ通信の違いがいまいちよく分りません。また、FOMA P2402とFOMA F2402は比較するとどちらの方が良いのでしょうか?

  • ポインター引数の関数でコンパイルエラーが出る。

    現在ATmega88というアトメル社製のマイコンのプログラミングを行っています。コンパイラはwin_avrを使用しています。 現在void tx_test(cc1101_client * client)というcc1101_clientポインターを引数とした関数を作成したのですが、この関数内でu16 tx_fifo_set(txfifo_data * txfifo)という txfifo_dataポインターを引数とする関数を呼び出したいと思っているのですが、これをコンパイルすると error: incompatible type for argument 1 of 'tx_fifo_set'というエラーが出力されコンパイルできない状態になります。なぜこのようなエラーになるのでしょうか? u16 tx_fifo_set(txfifo_data * txfifo) { -------------------(中略)------------------------------------------------------------- } void tx_test(cc1101_client * client) { u8 i=0; u8 new_input_data=0; -------------------(中略)------------------------------------------------------------- while(1) { switch(status) { -------------------(中略)------------------------------------------------------------- case FIFO_SETUP: if(cnt_sent_packet > 100) { status = DATA_WAVEOUT_QUIT; break; } //alert_data_get(&client); cc1100_cmd_flush_tx(); cc1100_cmd_idle(); cc1100_cmd_calibrate(); cc1100_cfg_gdo0(CC1100_GDOx_SYNC_WORD); mdelay(5); client->status.sessionflag = 0x02; //SYN flag set client->status.ivent_flag = 0xa5; //tx_length = tx_fifo_set(client); //tx_fifo_set(&client); tx_fifo_set(client->txfifo); udelay(10); #if 1 cc1100_read_reg_uartout((CC1100_REG_TXBYTES | CC1100_ACCESS_STATUS)); #endif status = DATA_WAVEOUT; break; -------------------(中略)------------------------------------------------------------- }

  • 1つのグローバル変数構造体に複数ポインタはできる?

    通信機能を常時チェックして、データが来るとそのデータを受信したら構造体の配列に一旦入れるというプログラムを行っております。 typedef struct _new_txfifo_data_ { u8 length; u8 idfy_id[3]; u16 dst_id[2]; u16 src_id[2]; u8 Packet_type; u8 Packet_version; u8 setup_mode; u8 Device_type; u8 version_major; u8 version_sub; u8 bat_val; u8 rssi; u8 lqi; u8 reg[20]; f_option_t opt; u8 s_rssi; u8 s_lqi; }fifo_t; 通常はこのデータ配列を受信するのですが、時々この構造体とは別のデータを受信することがあります。次のような構造体です。 typedef struct _ADJUST_ { packet_hdr_t hdr; u8 bat_val; u16 adc_temperature; u8 prog_ver_sub; u8 prog_ver_major; u8 Device_type; u8 adj_freq; u8 adj_temper; u8 freq_add_sub; u8 temper_add_sub; u8 level[7]; u8 rssi; u8 lqi; u8 id[3]; // f_option_t f_option; }adjust_t; このため次のようなプログラムを作成しました。 void main(void) { -------(中略)-------------------------------------------- fifo_t * fifo; adjust_t * pDD; fifo = &gClient.fifo; pDD = &gClient.fifo; -------(中略)-------------------------------------------- while(1) { length = cc1101_rx((u8 *)fifo,1); if(length > 0 ) { if(pDD->id[0] == 0x6d && pDD->id[1] == 0x65 && pDD->id[2] == 0x32) { OK++; } } -------(中略)-------------------------------------------- } } このプログラムをAVR Studio6.2の環境で作成しています。 しかし、このプログラムはビルドは成功するのですが、 fifo_t * fifo;側は&gClient.fifoのグローバル変数のアドレスをポイントできているようで、fifoの変数をマウスクリックすると入力支援を受けることができるのですが、adjust_t * pDD側はアドレスをポイントできていないようです。入力支援も受けられません。 pDDとfifoをwatch機能で見てみると ・pDD Optimized away Error ・fifo 0x01fa fifo_t*{data}@0x04e1 ([R28]+1) pDDは”Optimized away Error”と出てきます。 また、受信されたデータには pDD->id[0] = 'm' pDD->id[1] = 'e' pDD->id[2] = '2' というデータが入っているので、このデータでadjust_tのデータであるかを識別したいのですが、TRUEのOK++にブレイクしません。 C言語のポインタでは1つのグローバル変数に対して複数のポインタを設定するということはできないのでしょうか? また、このような受信されたデータの型が複数のある場合の良い対処法などご教授頂きますよう、お願い致します。

  • PIC16F1827のEEPROMへの書込み

    PCM V5.0(PIC用CCS社コンパイラ)を Mplab8.92に組込み、PICkit3を使ってプログラムしています。 PIC16F1827のEEPROMへの書込みがうまくいきません。 RAは入力ポートで固定してあります。 RBは出力ポートでLEDが接続してあります。 テストプログラムは一回のみの動作です。 実機で動作させると RAは固定してあるので当然(4)でLEDが点灯しますが、 実機からCPUを抜き取りMplab上でReadすると EEPROMのアドレス0,1,2は異なるデータであり 動作させるたびに違うデータが書込まれています。 しかし (1) a0=35h (2) a1=a6h (3) a2=93h と定数にすると EEPROMのアドレス0,1,2は正しいデータが 書込まれています。 Q1. a0,a1,a2をポート入力とする場合は CPU自体に何か設定する必要があるのでしょうか? それともプログラムに工夫が必要なのでしょうか? いままで使っていたPIC16F88では このようなことはなかったと思うのですが・・・。 ----- テストプログラム ----- a0 = RA; //(1) write_eeprom (0,a0); a1 = RA; //(2) write_eeprom (1,a1); a2 = RA; //(3) write_eeprom (2,a2); if (a0 == a1 && a1==a2) //(4) RB =255; else RB =0;

  • cpuとeeprom間のi2cバス通信の信頼性について教えてください

    I2Cバス通信の信頼性について教えてください。 cpuとeeprom間をI2Cバス通信で制御したく考えています。 その際、送受信のアドレスやデータのbitがこけたりして、データが書き換わってしまうことはありますか? 通常制御、あるいはノイズ環境での信頼性について分かる方がいましたら教えてください。 よろしくお願いします。

  • あるマクロ処理の処理内容についての質問

    閲覧して頂いてありがとうございます。 C言語を勉強中なのですが、あるプログラムの中に どんな『処理』をしているかわからないマクロ関数があります。 下記Sampleコードの『#define test(n,a,k)』ですが、 一体どのような処理をしているか、ご教授頂けないでしょうか。 漠然とした質問で申し訳ありませんが、よろしくお願い致します。 [Sampleコード] #include <stdio.h> #define UL unsigned long #define UC unsigned char #define test(n,a,k) \ { \ (n) = ((UL)a[k]) \ | ((UL)a[k + 1] << 8) \ | ((UL)a[k + 2] << 16) \ | ((UL)a[k + 3] << 24); \ } int main(void){ UC hoge[] = {"1234567890_1234567890_1234567890_1234567890_1234567890"}; UL buf[4]; UL i; UC *p; p = hoge; test(buf[0], p, 0); test(buf[1], p, 4); test(buf[2], p, 8); test(buf[3], p, 12); for(i = 0; i < sizeof(buf)/sizeof(buf[0]); i++){ printf("%d\n",buf[i]); } return 0; }