🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

mbed

mbed(エンベッド)は、Webサイト上でC++を使って開発を行う、ワンボードマイコンのプロトタイピングツールです。PCに開発環境をインストールする必要がなく、Webにアクセスできればどこにいても開発を行うことができます。

マイコン

マイクロコンピュータの略で、CPUにマイクロプロセッサを用いたコンピュータのこと。家電製品、電磁機器などの制御に用いられています。単体でコンピュータとしての機能を一通り備えています。 現代のパーソナルコンピュータに近く、同時期のメインフレームやミニコンピュータと比べ、小さいことが特徴です。

Q&A

解決済

3回答

1503閲覧

一つのスイッチでLEDの光り方を変化させるプログラム

sata0410

総合スコア2

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

mbed

mbed(エンベッド)は、Webサイト上でC++を使って開発を行う、ワンボードマイコンのプロトタイピングツールです。PCに開発環境をインストールする必要がなく、Webにアクセスできればどこにいても開発を行うことができます。

マイコン

マイクロコンピュータの略で、CPUにマイクロプロセッサを用いたコンピュータのこと。家電製品、電磁機器などの制御に用いられています。単体でコンピュータとしての機能を一通り備えています。 現代のパーソナルコンピュータに近く、同時期のメインフレームやミニコンピュータと比べ、小さいことが特徴です。

0グッド

1クリップ

投稿2020/12/07 07:02

前提・実現したいこと

c言語のmbedで一つのボタンを押したら光り方がいくつにも変化するプログラムを書いています。

発生している問題・エラーメッセージ

エラーコードは出ないのですが、LEDが光りません。

該当のソースコード

C言語

1//一つのスイッチであかり方が変化するプログラム 2#include"mbed.h" 3#include"stdio.h" 4#include"stdlib.h" 5#include"time.h" 6 7DigitalIn S1(A1); 8PwmOut L1(D1); 9PwmOut L2(D2); 10PwmOut L3(D3); 11PwmOut L4(D4); 12 13int main(){ 14 float a = 0.0f; 15 float b = 0.01f; 16 srand((/*unsigned */float)time(NULL)); 17 while(1){ 18 L1.period(0.00002f); 19 L2.period(0.00002f); 20 L3.period(0.00002f); 21 if (S1 == 1){ 22 while(S1 != 1){ 23 for(a = 0.0f;a <= 1.0f;a =+0.01f){ 24 L1.write(fabs(a)); 25 wait(b); 26 L1 = 0; 27 L2.write(fabs(a)); 28 wait(b); 29 L2 = 0; 30 L3.write(fabs(a)); 31 wait(b); 32 L3 = 0; 33 L4.write(fabs(a)); 34 wait(b); 35 L4 = 0; 36 } 37 } 38 while(S1 != 1){ 39 int g = rand()%4+1; 40 float c = g; 41 if(c == 1){ 42 L1 = 1; 43 }else if (c == 2){ 44 L2 = 1; 45 }else if (c == 3){ 46 L3 = 1; 47 }else if (c == 4){ 48 L4 = 1; 49 } 50 wait(b); 51 L1 = 0; 52 L2 = 0; 53 L3 = 0; 54 L4 = 0; 55 } 56 while(S1 != 1){ 57 int h = rand()%100+1; 58 float d = h*0.01f; 59 L1.write(fabs(d)); 60 wait(b); 61 L1 = 0; 62 L2.write(fabs(d)); 63 wait(b); 64 L2 = 0; 65 L3.write(fabs(d)); 66 wait(b); 67 L3 = 0; 68 L4.write(fabs(d)); 69 wait(b); 70 L4 = 0; 71 } 72 while(S1 != 1){ 73 int i = rand()%100+1; 74 float e = i*0.01f; 75 int f = rand()%4+1; 76 if(f == 1){ 77 L1.write(fabs(e)); 78 }else if(f == 2){ 79 L2.write(fabs(e)); 80 }else if(f == 3){ 81 L3.write(fabs(e)); 82 }else if(f == 4){ 83 L4.write(fabs(e)); 84 } 85 wait(b); 86 L1 = 0; 87 L2 = 0; 88 L3 = 0; 89 L4 = 0; 90 } 91 } 92 } 93}

試したこと

waitを動きの初めに入れてみました。

補足情報(FW/ツールのバージョンなど)

マイコン...Nucle-f303k8

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

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

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

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

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

guest

回答3

0

ベストアンサー

エラーコードは出ないのですが、LEDが光りません。

確かに上記コードのD1D4をLED1LED4にして動かしてみましたが
光らないようですね。

原因はy_waiwaiさんやthkanaさんの仰る通りだと思われます

恐らくボタンが押されるたびに
ゆっくり順番にLEDがゆっくり明るくなる動作を実行

デジタルな明るさでにバラバラな順序でLEDが点滅

決まった順序でバラバラな明るさにLEDが点滅

パラバラな順序でバラバラな明るさでLEDが点滅
という動作を繰り返すプログラムが作りたかったとするのなら

発光パターンを関数でまとめてそれを関数ポインタの配列で管理し、
グローバル変数で今実行すべき関数のインデックスを保管しておき、
GPIO割り込み発生で今実行すべき関数のインデックスを変更しするような
処理にすればよいかと思われます。

あと実際に確かめていないので間違ってるかもしれないですが
マイコンで乱数のシードはtime関数から取得しても
同じ値しか取れないのではないのでしょうか

先程シリアル通信を使いtime関数の出力を観測してみましたが
案の定いつまでたっても0しか吐きませんでした。
なので開放状態のアナログ入力からのほうが良いかもしれません。

尚手元にあったmbedがNucle-f303k8ではなくLPC1768だったので
LPC1768でしか動作確認は行っていません。

c++

1#include"mbed.h" 2#include"stdlib.h" 3#include "stdint.h" 4 5#define LED_NUM 4// LED数 6#define PATTERN_NUM 4// 発光パターン数 7 8// 9// ここからグローバルな変数定義 10// 11PwmOut leds[LED_NUM] = {PwmOut(D1), PwmOut(D2), PwmOut(D3), PwmOut(D4)}; 12uint8_t pattern = 0; 13 14// 15// ここから発光パターン 16// 17void pattern1() 18{ 19 for(uint8_t i=0; i<LED_NUM; ++i) 20 { 21 for(float duty_rethio = 0.f; duty_rethio <= 1.f; duty_rethio += 0.000005f) 22 leds[i] = duty_rethio; 23 24 leds[i] = 0.f; 25 } 26} 27 28void pattern2() 29{ 30 uint8_t rand_index = rand() % LED_NUM; 31 leds[rand_index] = 1.f; 32 wait(0.1f); 33 leds[rand_index] = 0.f; 34} 35 36void pattern3() 37{ 38 float rand_duty; 39 for(uint8_t i=0; i<LED_NUM; ++i) 40 { 41 rand_duty = static_cast<float>(rand())/RAND_MAX; 42 leds[i] = rand_duty; 43 wait(0.5f); 44 leds[i] = 0.f; 45 } 46} 47 48void pattern4() 49{ 50 float rand_duty = static_cast<float>(rand())/RAND_MAX; 51 uint8_t rand_index = rand() % LED_NUM; 52 leds[rand_index] = rand_duty; 53 wait(0.5f); 54 leds[rand_index] = 0.f; 55} 56 57// 58// 割り込み用コールバック 59// 60void push() 61{ 62 if(pattern >= PATTERN_NUM - 1) pattern = 0; 63 else ++pattern; 64 wait(0.15f);// 回路側でチャタリング防止を行っているならこの行は外してよい 65} 66 67// 68// メイン関数 69// 70int main(){ 71 InterruptIn sw(A1); 72 sw.rise(&push); 73 sw.mode(PullDown); 74 75 AnalogIn adc(A0); 76 srand(adc.read_u16()); 77 78 void(*pattern_list[PATTERN_NUM])() = {&pattern1, &pattern2, &pattern3, &pattern4}; 79 80 while(true) 81 { 82 pattern_list[pattern](); 83 for(uint8_t i=0; i<LED_NUM; ++i) leds[i] = 0.f; 84 } 85}

追記

上記の方法ではアナログ入力端子を一つ無駄にしてしまうので
下記の方法のほうが適切かと思われます。

電源がonになり、プログラムが開始した直後からボタンが初めて押されるまでの
時間をシード値とすることでグローバル変数が2つ増えてしまいますが
アナログ入力端子を無駄にせずに実装できそうです。(下記thkanaさんのコメント参照)

c++

1#include"mbed.h" 2#include"stdlib.h" 3#include "stdint.h" 4 5#define LED_NUM 4// LED数 6#define PATTERN_NUM 4// 発光パターン数 7 8// 9// ここからグローバルな変数定義 10// 11PwmOut leds[LED_NUM] = {PwmOut(D1), PwmOut(D2), PwmOut(D3), PwmOut(D4)}; 12uint8_t pattern = 0; 13Timer timer; 14bool srand_flag = true; 15 16// 17// ここから発光パターン 18// 19void pattern1() 20{ 21 for(uint8_t i=0; i<LED_NUM; ++i) 22 { 23 for(float duty_rethio = 0.f; duty_rethio <= 1.f; duty_rethio += 0.000005f) 24 leds[i] = duty_rethio; 25 26 leds[i] = 0.f; 27 } 28} 29 30void pattern2() 31{ 32 uint8_t rand_index = rand() % LED_NUM; 33 leds[rand_index] = 1.f; 34 wait(0.1f); 35 leds[rand_index] = 0.f; 36} 37 38void pattern3() 39{ 40 float rand_duty; 41 for(uint8_t i=0; i<LED_NUM; ++i) 42 { 43 rand_duty = static_cast<float>(rand())/RAND_MAX; 44 leds[i] = rand_duty; 45 wait(0.5f); 46 leds[i] = 0.f; 47 } 48} 49 50void pattern4() 51{ 52 float rand_duty = static_cast<float>(rand())/RAND_MAX; 53 uint8_t rand_index = rand() % LED_NUM; 54 leds[rand_index] = rand_duty; 55 wait(0.5f); 56 leds[rand_index] = 0.f; 57} 58 59// 60// 割り込み用コールバック 61// 62void push() 63{ 64 timer.stop(); 65 if(srand_flag) 66 { 67 srand(timer.read_us()); 68 srand_flag = false; 69 } 70 if(pattern >= PATTERN_NUM - 1) pattern = 0; 71 else ++pattern; 72 wait(0.15f);// 回路側でチャタリング防止を行っているならこの行は外してよい 73} 74 75// 76// メイン関数 77// 78int main(){ 79 InterruptIn sw(A1); 80 sw.rise(&push); 81 sw.mode(PullDown); 82 83 timer.start(); 84 85 void(*pattern_list[PATTERN_NUM])() = {&pattern1, &pattern2, &pattern3, &pattern4}; 86 87 while(true) 88 { 89 pattern_list[pattern](); 90 for(uint8_t i=0; i<LED_NUM; ++i) leds[i] = 0.f; 91 } 92}

投稿2020/12/08 22:04

編集2020/12/09 02:31
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

thkana

2020/12/08 23:23 編集

> マイコンで乱数のシードはtime関数から取得しても > 同じ値しか取れないのではないのでしょうか > なので開放状態のアナログ入力からのほうが良いかもしれません。 STM32って乱数発生器を積んでたはず...と思ったけどF303は積んでなかった。残念。 このプログラムなら、ボタンを押した直後にでも時刻をとればばらついた値が得られますね。
退会済みユーザー

退会済みユーザー

2020/12/09 02:28 編集

> ボタンを押した直後にでも時刻をとればばらついた値が得られますね。 確かにそのほうがアナログ入力1つ無駄にしなくても良さそうなので 適切かもしれませんね。 自分なりに考えたコードを回答に追記しておきます。
sata0410

2020/12/10 21:49

このプログラムは while(S1 != 1) のところに関数に番号を付けて、増加していくという考え方で会っているのでしょうか?
退会済みユーザー

退会済みユーザー

2020/12/10 23:26 編集

質問文コードのwhile(S1 != 1)で区切られている 発光パターンを関数にしてしまい。 それらを配列に入れてグローバル変数pattern番目の 関数を無限ループ内で処理し ボタンが押されたらそのグローバル変数patternの数値が 変化するのでボタンを押せば発光パターンが変わる。 という解釈でしたら合っているはずかと思われます。
sata0410

2020/12/11 07:01

教えていただきありがとうございます。なんとなくですが理解できた気がします。
guest

0

S1では「スイッチが押された」ことが得られるのではありません。
「スイッチが押されている」ことが得られます。この違いわかりますか?
押された、というのは、いままで押されていなかったのがいまは押されている、ということ。
押されている、というのは、以前は関係なく、とにかくいま押されていること。

スイッチが押されているかどうかのチェックはマイクロ秒(100万分の1秒)のオーダーで行われますから、if(S1==1)でスイッチが押されていることを検出したとしてその100万分の1秒後にはwhile(S1 != 1)でまたS1を調べて...まぁ普通はまだ押されたままですよね。あなたがよほど素早く=100万分の1秒以内にスイッチをオフにしない限り。S1 != 1は偽ですから、ループには入りません。その後も100万分の3秒以内に次々とwhile(S1 != 1)をすり抜けてif文は終わります。LEDが点灯するわけありません。

というのが現状。

もう一つ、それとは全く関係ないところですが、
for(a = 0.0f;a <= 1.0f;a =+0.01f){
よ~く見て下さい。a =+0.01fというのはどういう作用をしますか? aに+0.01fを代入する...ですよ。それはあなたのやりたいことでしょうか。

以上、「質問」には、現状報告しか書かれていないのでこちらも現状分析のみ。

投稿2020/12/08 07:53

thkana

総合スコア7703

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

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

sata0410

2020/12/10 21:45

スイッチの詳細なことを教えてくださりありがとうございます。そこのプログラムにはだんだんと明るく変化するつもりで書いてみました。
thkana

2020/12/10 22:53

> そこのプログラムにはだんだんと明るく変化するつもりで書いてみました。 なら、ソコはソコとして void pattern1() { float a=0.0f; float b=0.01; for (a = 0.0f; a <= 1.0f; a += 0.01f) { L1.write(fabs(a)); wait(b); L1 = 0; L2.write(fabs(a)); wait(b); L2 = 0; L3.write(fabs(a)); wait(b); L3 = 0; L4.write(fabs(a)); wait(b); L4 = 0; } } int main(){ while(1){ pattern1(); } } などとすれば意図するパターンで変化しているか確認できるでしょう。(他も同様)
sata0410

2020/12/11 07:01

教えていただきありがとうございます。試してみたいと思います
guest

0

if (S1 == 1){

S1関数のアドレスを比較してますが、これでいいんでしょうか

投稿2020/12/07 07:33

y_waiwai

総合スコア88038

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

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

sata0410

2020/12/07 07:46

そのコードはスイッチが押された時を認識するために書いたんですが、どのようにすればよろしいと思いましか?
y_waiwai

2020/12/07 07:59

その書き方で合ってるようですね、失礼しました ましかし、 if (S1 == 1){ while(S1 != 1){ ... } while(S1 != 1){ ... } while(S1 != 1){ ... } while(S1 != 1){ ... } } というコードとなってますが、 最初のif文でS1が1のときにナカミが実行されると、その中のWhile文は実行されないことになりますが、これもおかしいですね
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問