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

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

ただいまの
回答率

88.80%

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

受付中

回答 3

投稿

  • 評価
  • クリップ 0
  • VIEW 345

Sunny5

score 0

前提・実現したいこと

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秒で全点灯や、フェード等を実施するためにはもっと良い書き方があるのでしょうか?
ご教授いただければ幸いです。

該当のソースコード

#include <stdio.h>
#include <stdlib.h>
#define LEDWAIT 20
#define LEDWAIT1 50
#define LEDWAIT2 100
#define LEDWAIT3 500
#define T0COUT     61   // タイマー0用カウントの初期値(256 - 195 = 61)

// CONFIG1 PIC16f886
#pragma config FOSC = INTRC_CLKOUT// Oscillator Selection bits (RC oscillator: CLKOUT function on RA6/OSC2/CLKOUT pin, RC on RA7/OSC1/CLKIN)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled and can be enabled by SWDTEN bit of the WDTCON register)
#pragma config PWRTE = OFF       // Power-up Timer Enable bit (PWRT enabled)
#pragma config MCLRE = OFF       // RE3/MCLR pin function select bit (RE3/MCLR pin function is MCLR)
#pragma config CP = OFF         // Code Protection bit (Program memory code protection is disabled)
#pragma config CPD = OFF        // Data Code Protection bit (Data memory code protection is disabled)
#pragma config BOREN = OFF       // Brown Out Reset Selection bits (BOR enabled)
#pragma config IESO = OFF       // Internal External Switchover bit (Internal/External Switchover mode is disabled)
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enabled bit (Fail-Safe Clock Monitor is disabled)
#pragma config LVP = OFF         // Low Voltage Programming Enable bit (RB3/PGM pin has PGM function, low voltage programming enabled)

// CONFIG2
#pragma config BOR4V = BOR40V   // Brown-out Reset Selection bit (Brown-out Reset set to 4.0V)
#pragma config WRT = OFF        // Flash Program Memory Self Write Enable bits (Write protection off)

// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.

#include <xc.h>
#include <htc.h>
#define _XTAL_FREQ 8000000

//int anodepinB[11] = { 0x07, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x38, 0xC0, 0x00 };
//int anodepinC[11] = { 0x00, 0x00, 0x01, 0x0F, 0x7F, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0x0E };

//int cathodepin[11] = { 0x40, 0x40, 0x40, 0x40, 0x40, 0x43, 0x7F, 0x00, 0x80, 0x80, 0x80 };
int cat = 0;
int Count ;                     // タイマーの割込み発生回数をカウントする変数
//int LEDflg ;                    // LEDのON/OFF状態フラグ
int LedB6,LedB5,LedB4,LedB3,LedB2,LedB1,LedB0 ;                     //B6用PWM閾値


void PICinit(){
    OSCCON     = 0b01110000 ; // 内部クロックは8MHz
    ANSEL = 0b00000000; // ANを全てオフ
    TRISA = 0b00000000; // RAピンは全て出力
    TRISB = 0b00000000; // RBピンは全て出力
    TRISC = 0b00000000; // RC3/RC4は入力
    PORTA = 0b00000000; //RA出力ピンを初期化(LOW)
    PORTB = 0b00000000; //RB出力ピンを初期化(LOW)
    PORTC = 0b00000000; // RC出力ピンを初期化(LOW)
    OPTION_REG = 0b00000000 ; // デジタルI/Oに内部プルアップ抵抗を使用する

    return;
}

// タイマー割込みの処理
void __interrupt() InterTimer( void )
{
     if (TMR2IF == 1) {           // タイマー2の割込み発生か?
          Count++ ;               // 割込み発生の回数をカウントする
          TMR2IF = 0 ;            // タイマー2割込フラグをリセット
          if (Count < LedB6) {      // 割込みを125回カウントすると約1秒
              RB6 = 1;
              RB7 = 1;
          }if(Count < LedB5){
              RB5  = 1;
              RC0 = 1;
          }if (Count < LedB4) {      // 割込みを125回カウントすると約1秒
              RB4 = 1;
              RC1 = 1;
          }
          if(Count < LedB3){
              RB3 = 1;
             // RC2 = 1;
          }if(Count < LedB2){
              RB2 = 1;
              RC3 = 1;
          }if(Count < LedB1){
              RB1 = 1;
              RC4 = 1;
          }if(Count < LedB0){
              RB0 = 1;
              RC5 = 1;
          }else{
              PORTB = 0x00;
              PORTC = 0x00;
          }
            Count++;
            if(Count == 100){
                Count = 0;
            }
     }
}

int main(void){
    PICinit();      //PICを初期化
    // カソードのループ
    unsigned short int i;
    T2CON  = 0b00000101 ;    // TMR2プリスケーラ値を64倍、ポストスケーラ値は1:1の設定
     PR2    = 249 ;           // タイマーのカウント値を設定
     TMR2   = 0 ;             // タイマー2の初期化
     Count  = 0 ;             // 割込み発生の回数カウンターを0にする

     TMR2IF = 0 ;             // タイマー2割込フラグを0にする
     TMR2IE = 1 ;             // タイマー2割込みを許可する
     PEIE   = 1 ;             // 周辺装置割り込み有効
     GIE    = 1 ;             // 全割込み処理を許可する

     //LEDflg = 0 ;             // LEDのフラグ状態をOFFとする

    while(1){

        for(i=0; i<=80;i++){
            if (i <= 10){    
            LedB6 = i*5;
            LedB5 = 0;
            LedB4 = 0;
            LedB3 = 0;
            LedB2 = 0;
            LedB1 = 0;
            LedB0 = 0;
            }else if (i > 10 && i<= 20){
                LedB6 = i*5;
                LedB5 = (i*5)-50;
                LedB4 = 0;
                LedB3 = 0;
                LedB2 = 0;
                LedB1 = 0;
                LedB0 = 0;
            }else if (i > 20 && i<= 30){
                LedB6 = 100;
                LedB5 = (i*5)-50;
                LedB4 = (i*5)-100;
                LedB3 = 0;
                LedB2 = 0;
                LedB1 = 0;
                LedB0 = 0;
            }else if (i > 30 && i<= 40){
                LedB6 = 100;
                LedB5 = 100;
                LedB4 = (i*5)-100;
                LedB3 = (i*5)-150;
                LedB2 = 0;
                LedB1 = 0;
                LedB0 = 0;
            }else if (i > 40 && i<= 50){
                LedB6 = 100;
                LedB5 = 100;
                LedB4 = 100;
                LedB3 = (i*5)-150;
                LedB2 = (i*5)-200;
                LedB1 = 0;
                LedB0 = 0;
            }else if (i > 50 && i<= 60){
                LedB6 = 100;
                LedB5 = 100;
                LedB4 = 100;
                LedB3 = 100;
                LedB2 = (i*5)-200;
                LedB1 = (i*5)-250;
                LedB0 = 0;
            }else if (i > 60 && i<= 70){
                LedB6 = 100;
                LedB5 = 100;
                LedB4 = 100;
                LedB3 = 100;
                LedB2 = 100;
                LedB1 = (i*5)-250;
                LedB0 = (i*5)-300;
            }else {
                LedB6 = 100;
                LedB5 = 100;
                LedB4 = 100;
                LedB3 = 100;
                LedB2 = 100;
                LedB1 = 100;
                LedB0 = (i*5)-300;
            }
            __delay_ms(10);
        }
    }return 0;
}

試したこと

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

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

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

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

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

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

0

回答ではないですが、

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

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

RB6 = 1;
RB7 = 1;

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

に変更してみて下さい

参考
Read Modify Write Problem

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

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という考えです。

![イメージ説明](bc1e8767fe830c9dadc644fe936f62cc.png)

※見本にするようなものでは無いです。単に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 ;
やプリスケーラあたりを変えて、割り込み周期を変えた方が楽です。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

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

  • ただいまの回答率 88.80%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る