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

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

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

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

プログラミング言語

プログラミング言語はパソコン上で実行することができるソースコードを記述する為に扱う言語の総称です。

マイコン

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

Q&A

3回答

3149閲覧

PIC16F886でLED調光制御の際にPORTBが暗くなる問題

Sunny5

総合スコア0

C

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

プログラミング言語

プログラミング言語はパソコン上で実行することができるソースコードを記述する為に扱う言語の総称です。

マイコン

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

0グッド

0クリップ

投稿2020/08/17 21:31

前提・実現したいこと

PIC16F886を利用してLEDを調光制御しつつシーケンシャルウィンカーのような動作をさせています。
具体的には、下記ポートにそれぞれLEDを接続し、それらを中央(LED7,8)から徐々に明るくさせながら外側(LED1,14)まで順番に点灯させる、といった動作をさせたいと考えております。
また、1つめのLEDが明るくなるまで(0⇒100%点灯)に100msかけるとすると、次に光るLEDは、前のLEDの明るさが50%になったタイミング(50ms)でONにしたいと考えています。

###ポート接続(LEDは上から順番に横並びで並べています)
PORTB0:LED1
PORTB1:LED2
PORTB2:LED3
PORTB3:LED4
PORTB4:LED5
PORTB5:LED6
PORTB6:LED7
PORTB7:LED8
PORTC0:LED9
PORTC1:LED10
PORTC2:LED11
PORTC3:LED12
PORTC4:LED13
PORTC5:LED14

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

下記のプログラムを実行すると、PORTC側は明るく光るのですが、PORTB1~PORTB5までの5つのポートのみ他より暗く光ってしまいます。 これらはPICの設定の問題でしょうか?それともプログラムの書き方が良くないのでしょうか? LED1つずつを個別にPWM制御しながら、n秒で全点灯や、フェード等を実施するためにはもっと良い書き方があるのでしょうか? ご教授いただければ幸いです。

該当のソースコード

C言語(PIC,MPLABX,XC8)

1#include <stdio.h> 2#include <stdlib.h> 3#define LEDWAIT 20 4#define LEDWAIT1 50 5#define LEDWAIT2 100 6#define LEDWAIT3 500 7#define T0COUT 61 // タイマー0用カウントの初期値(256 - 195 = 61) 8 9// CONFIG1 PIC16f886 10#pragma config FOSC = INTRC_CLKOUT// Oscillator Selection bits (RC oscillator: CLKOUT function on RA6/OSC2/CLKOUT pin, RC on RA7/OSC1/CLKIN) 11#pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled and can be enabled by SWDTEN bit of the WDTCON register) 12#pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT enabled) 13#pragma config MCLRE = OFF // RE3/MCLR pin function select bit (RE3/MCLR pin function is MCLR) 14#pragma config CP = OFF // Code Protection bit (Program memory code protection is disabled) 15#pragma config CPD = OFF // Data Code Protection bit (Data memory code protection is disabled) 16#pragma config BOREN = OFF // Brown Out Reset Selection bits (BOR enabled) 17#pragma config IESO = OFF // Internal External Switchover bit (Internal/External Switchover mode is disabled) 18#pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enabled bit (Fail-Safe Clock Monitor is disabled) 19#pragma config LVP = OFF // Low Voltage Programming Enable bit (RB3/PGM pin has PGM function, low voltage programming enabled) 20 21// CONFIG2 22#pragma config BOR4V = BOR40V // Brown-out Reset Selection bit (Brown-out Reset set to 4.0V) 23#pragma config WRT = OFF // Flash Program Memory Self Write Enable bits (Write protection off) 24 25// #pragma config statements should precede project file includes. 26// Use project enums instead of #define for ON and OFF. 27 28#include <xc.h> 29#include <htc.h> 30#define _XTAL_FREQ 8000000 31 32//int anodepinB[11] = { 0x07, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x38, 0xC0, 0x00 }; 33//int anodepinC[11] = { 0x00, 0x00, 0x01, 0x0F, 0x7F, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0x0E }; 34 35//int cathodepin[11] = { 0x40, 0x40, 0x40, 0x40, 0x40, 0x43, 0x7F, 0x00, 0x80, 0x80, 0x80 }; 36int cat = 0; 37int Count ; // タイマーの割込み発生回数をカウントする変数 38//int LEDflg ; // LEDのON/OFF状態フラグ 39int LedB6,LedB5,LedB4,LedB3,LedB2,LedB1,LedB0 ; //B6用PWM閾値 40 41 42void PICinit(){ 43 OSCCON = 0b01110000 ; // 内部クロックは8MHz 44 ANSEL = 0b00000000; // ANを全てオフ 45 TRISA = 0b00000000; // RAピンは全て出力 46 TRISB = 0b00000000; // RBピンは全て出力 47 TRISC = 0b00000000; // RC3/RC4は入力 48 PORTA = 0b00000000; //RA出力ピンを初期化(LOW) 49 PORTB = 0b00000000; //RB出力ピンを初期化(LOW) 50 PORTC = 0b00000000; // RC出力ピンを初期化(LOW) 51 OPTION_REG = 0b00000000 ; // デジタルI/Oに内部プルアップ抵抗を使用する 52 53 return; 54} 55 56// タイマー割込みの処理 57void __interrupt() InterTimer( void ) 58{ 59 if (TMR2IF == 1) { // タイマー2の割込み発生か? 60 Count++ ; // 割込み発生の回数をカウントする 61 TMR2IF = 0 ; // タイマー2割込フラグをリセット 62 if (Count < LedB6) { // 割込みを125回カウントすると約1秒 63 RB6 = 1; 64 RB7 = 1; 65 }if(Count < LedB5){ 66 RB5 = 1; 67 RC0 = 1; 68 }if (Count < LedB4) { // 割込みを125回カウントすると約1秒 69 RB4 = 1; 70 RC1 = 1; 71 } 72 if(Count < LedB3){ 73 RB3 = 1; 74 // RC2 = 1; 75 }if(Count < LedB2){ 76 RB2 = 1; 77 RC3 = 1; 78 }if(Count < LedB1){ 79 RB1 = 1; 80 RC4 = 1; 81 }if(Count < LedB0){ 82 RB0 = 1; 83 RC5 = 1; 84 }else{ 85 PORTB = 0x00; 86 PORTC = 0x00; 87 } 88 Count++; 89 if(Count == 100){ 90 Count = 0; 91 } 92 } 93} 94 95int main(void){ 96 PICinit(); //PICを初期化 97 // カソードのループ 98 unsigned short int i; 99 T2CON = 0b00000101 ; // TMR2プリスケーラ値を64倍、ポストスケーラ値は1:1の設定 100 PR2 = 249 ; // タイマーのカウント値を設定 101 TMR2 = 0 ; // タイマー2の初期化 102 Count = 0 ; // 割込み発生の回数カウンターを0にする 103 104 TMR2IF = 0 ; // タイマー2割込フラグを0にする 105 TMR2IE = 1 ; // タイマー2割込みを許可する 106 PEIE = 1 ; // 周辺装置割り込み有効 107 GIE = 1 ; // 全割込み処理を許可する 108 109 //LEDflg = 0 ; // LEDのフラグ状態をOFFとする 110 111 while(1){ 112 113 for(i=0; i<=80;i++){ 114 if (i <= 10){ 115 LedB6 = i*5; 116 LedB5 = 0; 117 LedB4 = 0; 118 LedB3 = 0; 119 LedB2 = 0; 120 LedB1 = 0; 121 LedB0 = 0; 122 }else if (i > 10 && i<= 20){ 123 LedB6 = i*5; 124 LedB5 = (i*5)-50; 125 LedB4 = 0; 126 LedB3 = 0; 127 LedB2 = 0; 128 LedB1 = 0; 129 LedB0 = 0; 130 }else if (i > 20 && i<= 30){ 131 LedB6 = 100; 132 LedB5 = (i*5)-50; 133 LedB4 = (i*5)-100; 134 LedB3 = 0; 135 LedB2 = 0; 136 LedB1 = 0; 137 LedB0 = 0; 138 }else if (i > 30 && i<= 40){ 139 LedB6 = 100; 140 LedB5 = 100; 141 LedB4 = (i*5)-100; 142 LedB3 = (i*5)-150; 143 LedB2 = 0; 144 LedB1 = 0; 145 LedB0 = 0; 146 }else if (i > 40 && i<= 50){ 147 LedB6 = 100; 148 LedB5 = 100; 149 LedB4 = 100; 150 LedB3 = (i*5)-150; 151 LedB2 = (i*5)-200; 152 LedB1 = 0; 153 LedB0 = 0; 154 }else if (i > 50 && i<= 60){ 155 LedB6 = 100; 156 LedB5 = 100; 157 LedB4 = 100; 158 LedB3 = 100; 159 LedB2 = (i*5)-200; 160 LedB1 = (i*5)-250; 161 LedB0 = 0; 162 }else if (i > 60 && i<= 70){ 163 LedB6 = 100; 164 LedB5 = 100; 165 LedB4 = 100; 166 LedB3 = 100; 167 LedB2 = 100; 168 LedB1 = (i*5)-250; 169 LedB0 = (i*5)-300; 170 }else { 171 LedB6 = 100; 172 LedB5 = 100; 173 LedB4 = 100; 174 LedB3 = 100; 175 LedB2 = 100; 176 LedB1 = 100; 177 LedB0 = (i*5)-300; 178 } 179 __delay_ms(10); 180 } 181 }return 0; 182} 183

試したこと

①動作はブレッドボード上で行っておりますが、ブレッドボードの接触不良等ではないことを確認済みです。(ほかのポートにさしても明るいポートとくらいポートは変わらなかったため)

②マイコンの内部プルアップ機能を有効にしているのが原因かと思い、無効にしたりしてみましたがだめでした。

③PORTBをPORTAに変更するときちんと明るく動作しますが、他の接続の関係でピン数が足りないため、PORTBを明るくして対応したいです。

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

MPLABX,Pickit3,xc8コンパイラを利用しています。
回路的には、よくある、マイコン⇒トランジスタ⇒LEDといったスイッチングの回路になっています。すべてのポートに対して回路構成は同じですが、マイコンの各ポートの機能やその設定によっておきてしまっている不具合なのでしょうか?
タイマーと干渉している可能性はあるかも、と思ったのですが私にはわかりませんでした・・・

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

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

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

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

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

guest

回答3

0

諸々、おかしい箇所はありますけど、特におかしいと思うのは

if(Count < LedB0){
RB0 = 1;
RC5 = 1;
}else{
PORTB = 0x00;
PORTC = 0x00;
}

これだと、大半の時間はLedB0の値は0ですから、上部で点灯させたものも
ここですぐに消灯されます。つまり、RB0とRC5(両端)以外はまともじゃない筈だけど。

あとは、

・#pragma config FOSC = INTRC_CLKOUT

・内部プルアップ有効

・T2CON = 0b00000111 →この値だとプリスケーラは4
タイマー500kHz→割り込み2kHz
Countの周波数20Hz=0.05sになると思う

・「// 割込みを125回カウントすると約1秒」といったコメント
システム的に、メインループでタイミングを取って、この割り込み自体は高速で回して、
即座にその明るさにする、という構成だと思うのだけども、なんでこんなにとぼけたコメントが付いているのか?
※コメント内容と時間が違うし、コメント通りの周期なら、遅すぎるのでは?

で、この位の速度なら、そのまま点灯させれば良いと思うのですけど、それでは駄目ですか?
ぶっちゃけ、他の作業(7セグ?)もあるようですから、それとの両立は難しくなるかもしれません。
(内蔵クロックがもっと出せるPICを選択するとか)

また、プログラム的にも、ピン数的にも、『各ピンで2LED制御した方』が良いです。(並列接続)

で、こういったものの書き方は、人それぞれでしょうけど、私は取りあえず図を書いてから考えます。
添付図は、割り込みの周波数2kHzのままで、希望動作(0→100%までが0.1s)でどんな感じなのかを書きました。
上で述べたように、並列で、PORTBの8ピン=計16LEDという考えです。

イメージ説明

※見本にするようなものでは無いです。単に1例(テキトー)です。

#define led_on(pin) (PORTB|=(1<<pin)) #define led_off(pin) (PORTB &=~(1<<pin)) #define led_all_off() PORTB=0

と書いておいて、↓を割り込み関数内に書けば動くんじゃないかな。
※そのLEDの点灯開始と消灯のタイミングをカウント値で操作する

if (TMR2IF == 1) { TMR2IF = 0 ; static int count=0;//大元になる、カウント回数 int pin_l=count/100;//対象になるピン下側 int pin_h=pin_l-1;//対象になるピン上側 int tmr=count%10;//カウント位置(図での高さ) int times=count%100/10;//サイクルあたりの回数(図でのXの位置) if(count==1000)led_all_off(); if(pin_l>=0 && pin_l<8) { if(tmr==0)led_on(pin_l); if(tmr==times/2)led_off(pin_l); } if(pin_h>=0 && pin_h<8) { if(tmr==0)led_on(pin_h); if(tmr==5+times/2 && (times!=9))led_off(pin_h); } if(++count==1100)count=0; }

メインのループ部は何もしないで良い。
使わない変数は消しておいて。

速度を変えるなら元の
PR2 = 249 ;
やプリスケーラあたりを変えて、割り込み周期を変えた方が楽です。

投稿2020/08/18 18:12

nac_tnk

総合スコア463

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

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

0

Read-Modify-Write 命令を連続で実行した時の誤作動だと思われます
また PIC実行時は、PICkit3 を外します ( ICSPDAT,ICSPCLK ピンは4.7kΩでプルダウンされています )

RB6 = 1;
RB7 = 1;

RB6 = 1;
NOP();
RB7 = 1;

に変更してみて下さい

参考
Read Modify Write Problem

投稿2020/08/18 00:07

koujikuu

総合スコア401

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

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

0

回答ではないですが、

こういう場合は、オシロスコープなどで各LEDにつながるポート出力の波形を見て、きちんと5V-0Vのスイングになってるかを見ます。
そのうえで、PWM波形を見て、デューティが想定の値になってるかをチェックしましょう。

投稿2020/08/17 23:33

y_waiwai

総合スコア87774

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問