質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.47%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

解決済

1回答

213閲覧

PICマイコンでのLチカが動作不安定

zusu0615

総合スコア1

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

0クリップ

投稿2024/04/12 05:13

編集2024/04/12 05:18

実現したいこと

1000msec毎、LEDを点灯/消灯したい。
(タイマー割込みを使用して)

発生している問題・分からないこと

発生している事象
・1000msec毎のトグルが、ときどき800msecくらいになってしまう。

該当のソースコード

uint16_t gMSecTime; // タイマー割込み関数 void Timer0IntFunc(void) { gMSecTime++; } /* Main application */ void main(void) { uint16_t t_led_tgl = 0; // time scale for LED uint16_t diff; // Initialize the device SYSTEM_Initialize(); TMR0_SetInterruptHandler(Timer0IntFunc); // タイマー0割込み関数の登録 // Enable the Global Interrupts INTERRUPT_GlobalInterruptEnable(); // Enable the Peripheral Interrupts INTERRUPT_PeripheralInterruptEnable(); t_led_tgl = gMSecTime; while (1) { diff = gMSecTime - t_led_tgl; // 経過時間計算 if( diff >= 1000 ){ // 1000msec経過? // ログ出力 sprintf(line_buf, "%u,%u,%u\r\n", gMSecTime, t_led_tgl, diff ); TxString(line_buf,strlen(line_buf)); IO_RA2_Toggle(); // LEDトグル t_led_tgl = gMSecTime; // 時間再計測 } } }

試したこと・調べたこと

  • teratailやGoogle等で検索した
  • ソースコードを自分なりに変更した
  • 知人に聞いた
  • その他
上記の詳細・結果

---以下、ログ出力-----------------------------
11195,10195,1000
12216,11216,1000
13056,12237,1074 ★この時、時間が短くなる。
14077,13077,1000
15098,14098,1000
16119,15119,1000

★の箇所で
gMSecTime:13056
t_led_tgl:12237
なので、
diff:819
となり、ifの条件に引っかからないはずなのですが
diff:1074
となっておりifの条件に引っかかってトグル処理を実行しています。
引き算の結果が時々おかしくなる!?

気になっているのは、
PIC18Fは8bitマイコンですがgMSecTimeが16bitなので
何か弊害があるのでは・・・
と思っています。

補足

今回初めてのPICマイコンでLチカを試しているのですが、どうもうまく動きません。
行き詰ってしまったため、お助けいただけると幸いです。

使用しているマイコンは「PIC18F14K22」で
MPLAB X IDEのMCCで初期化コードを生成しています。

アルゴリズムは下記のようにしています。
・タイマ0を使って1msecの周期割込みを発生
・割込み処理内で1msecカウンタgMSecTimeをインクリメント
・mainループで1msecカウンタgMSecTimeを監視
・1000msec経過したら、LED(IOポートRA2)をトグル

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ikedas

2024/04/12 09:54

回答ではないのでこちらのコメントに書きますが、 ・PICのCコンパイラの仕様を知らないのですが、ご提示のコードではgMSecTimeは初期化されていないので、実行時の初期値は不定になるかもしれません。 ・いずれにせよ、長くても1分余経てばオーバフローします。このときの動作もPICやコンパイラの仕様により、クラッシュするか想定外の挙動をするかでしょう、
guest

回答1

0

ベストアンサー

まず、

uint16_t gMSecTime;

割り込みで値を変えるのであれば、この変数宣言にはvolatile を付ける必要があります

volatile uint16_t gMSecTime;

んで、お使いのPICの型番がわかりませんが、純粋に8bitごとのアクセスしかできない機種なのであれば、メインルーチンでのgMSecTime変数を読み込む場合、下位バイトを読んで、上位バイトを読む間に割り込みがかかって値が更新されてしまうと、ワケワカメとなってしまうので、この変数を読み出すときには割り込みを禁止しておく必要があります

んでもひとつ、main関数の中で何回もこの変数を読んでますが、こいつは割り込みで勝手に値が変わるため、そいつを考慮する必要があります
時間を計算する個所とプリントする個所では値が変わっているかもしれません。

投稿2024/04/12 05:39

y_waiwai

総合スコア87784

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

zusu0615

2024/04/12 06:33

回答ありがとうございます。 ご指摘の通り、経過時間を計算する処理 diff = gMSecTime - t_led_tgl; を割込み禁止にすることで正常動作しました。 >お使いのPICの型番がわかりませんが 使用しているマイコンは「PIC18F14K22」で8bitマイコンです。 >下位バイトを読んで、上位バイトを読む間に割り込みがかかって 恐らくこれが発生していたと思われます。 8bitCPUで16bit,32bitの変数を扱う場合、 こういう気遣いが必要なのですね・・・ 勉強になりました。 ベストアンサーに選ばせていただきました。
y_waiwai

2024/04/12 07:47

その変数を読む場合に割り込み禁止にするってのは手っ取り早くていいんですが、割り込み禁止にしたくないという場合には、 その変数を2回連続で読み、双方の値が同一ならそれを採用する(違う場合は読み直しする)、という手も使えます。 まあ、割り込み周期が1msとはっきりしている場合に使える手ですが。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.47%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問