閲覧総計:8367  (本日:1  昨日:0)

A/D價でLEDの蓂るさ匾曬(PWM LCD表示 16F1827 XC8)

a href="https://fr.chaturbate.eu.com/" rel="nofollow">chaturbate</a> login

a href="https://de.chaturbate.eu.com/" rel="nofollow">chaturbate</a>

a href="https://pl.chaturbate.eu.com/" rel="nofollow">chaturbate</a> now login

a href="https://nl.chaturbate.eu.com/" rel="nofollow">chaturbate</a>

a href="https://jp.chaturbate.eu.com/" rel="nofollow">chaturbate</a> login now

PICに液晶ディスプレー(LCD)が接続できる様になると、PICの動いている状態
をビジュアルで確認出来る様になりとても便利です。
PICの細かな動きが数値で確認できる様になり、細かい補正を行う事が可能に
なります。
LCDへの数値表示により、今回はADC値(50-1023)を-50補正しPWMのduty値
(0-973)にするのが良い事の気付きがありました。

機能:可変抵抗器のアナログ値をデジタル変換し、その値でPWMのduty値を変化
させLEDの明るさをなめらかに変更する。また、dutycycle値、duty値をLCDに
表示する。                 2014/1/11

TS3V0016.JPGduty17%のロジアナ画面.jpgadc値でLED明るさ変更LCDに値表示プログラム画面.jpg
/* A/D値で発光ダイオード(LED)の明るさをPWM機能で変更する
 * またPWMのduty値をI2C LCDに表示する
 * PIC16F1827
 * XC8 v1.20
 * LED:RA2,RA3
 * 可変抵抗(10kΩ):RB5
 * I2C SDA:SDA1(RB1) pin7
 * I2C SCL:SCL1(RB4) pin10
 */
#include <xc.h>
#pragma config FOSC = INTOSC, WDTE = OFF, BOREN = OFF, IESO = OFF, FCMEN = OFF
#pragma config PLLEN = OFF, STVREN = OFF, LVP = OFF

//__delay_us(), __delay_ms()へのクロック情報の設定
#define _XTAL_FREQ 8000000 //PICのクロックをHzで設定(8MHz)

//関数のプロトタイプ宣言
extern void itostring(char digit, unsigned int data, char *buffer);
extern unsigned int read_a2d(unsigned char channel);
extern void arg_delay_ms(unsigned int x);

void i2cByteWrite(char, char, char);    // i2c byte送信
void i2cTxData(char);                   // i2c SSPBUF セット
void LCD_dat(char);                     // 1文字表示
void LCD_cmd(char);                     // コマンド出力
void LCD_clr(void);                     // 全消去
void LCD_int(void);                     // 初期化
void LCD_str(char *);                   // 文字列表示
void LCD_ROMstr(const char *);          // ROM文字列表示
void LCD_posyx(char,char);              // カーソル位置指定
void LCD_hex(char);                     // 16進文字変換表示

int main(void) {
    //使用変数の定義
    unsigned int adc_val; //ADC値の結果(0-1023)
    unsigned int dutycycle; //PWM duty(0〜1000)
    unsigned char s_dutycycle[6]; //LCD表示用文字列
    unsigned int duty; //duty%値
    unsigned char s_duty[6]; //LCD表示用文字列

    //PICの初期設定
    PORTA = 0b00000000; //PORTAの中身をきれいにする
    PORTB = 0b00000000; //PORTBの中身をきれいにする
    TRISA = 0b00000000; //PORTA全てを0:出力に設定
    TRISB = 0b11111111; //PORTBは全て1:入力に設定
    ANSELA = 0b00000000; //RA4(AN4)-RA0(AN0)は全て0:デジタルI/Oとする
    ANSELB = 0b00100000; //RB5(AN7)のみ1:アナログ、他は0:デジタルI/Oとする
    OSCCON = 0b01110000; //PLL:OFF, 内部クロック8MHzで駆動
    OPTION_REGbits.nWPUEN = 0; // 0:PORTB内部プルアップ利用に設定
    WPUBbits.WPUB1 = 1; // RB1をI2C通信のウィークプルアップ
    WPUBbits.WPUB4 = 1; // RB4をI2C通信のウィークプルアップ

    //CCP3(RA3)へPWM信号を出力(Timer2使用)
    //PWM各種設定値の計算
    //クロック8MHz Tosc = 0.125μsの時
    //2000HzのPWM信号を発信する場合
    //
    //周期 = 2000Hz = 1/2000 = 500μs
    //(PR2の範囲は0〜255)
    //Timer2のプリスケール 4
    //周期 = (PR2 + 1) * 4 * Tosc * (Timer2のプリスケール値)であるから
    //PR2 = (周期 / (4 * Tosc * (Timer2のプリスケール値)) - 1
    //PR2 = (500 / (4 * 0.125 * 4)) - 1
    //PR2 = 249
    //
    //PWM分解能 DC1(Max)は
    //duty = DC1 * Tosc * (Timer2のプリスケール値)であるから
    //DC1 = duty / (Tosc * (Timer2のプリスケール値))
    //DC1(Max) = 500 / (0.125 * 4)
    //DC1(Max) = 1000

    //PWM各種条件設定
    //CCP3(RA3)へPWM信号を出力
    CCPTMRS = 0b00000000; //CCP3はTimer2使用に設定
    CCP3CON = 0b00001100; //PWMモードを使用する
    T2CON = 0b00000001; ////プリスケール 4に設定
    PR2 = 249; //PWM周波数2000Hzに設定
    TMR2 = 0; //Timer2カウンターをクリアー
    T2CONbits.TMR2ON = 1; //Timer2 ON

    //I2C通信の初期設定
    SSPCON1 = 0b00101000;          // I2Cマスターモード指定
    SSPSTAT = 0b00000000;          // I2C STATUSの設定
    SSPADD  = 19;                  // I2Cクロック周波数100KHz(=(19+1)*4/8MHz)

    //A2D変換開始
    ADCON1 = 0b10010000; //select right justify result, ADCS Fosc/8, A/D port configuratio  n 0
    ADCON0bits.ADON = 1; //ADON

    //メイン処理
    LATAbits.LATA2 = 1; //RA2:パワーオンを示すLED点灯(かつ照度比較用LED)
    LCD_int(); // LCD初期化
    LCD_ROMstr("duty val ="); // 1行目に表示
    LCD_posyx(1,0); // 2行目頭にカーソル移動
    LCD_ROMstr("duty% =");

    while(1) {
        //アナログデータの取得 10bit(0~1023)
        adc_val = read_a2d(7); //RB5(AN7)のアナログ値読み込み
        dutycycle = adc_val - 50; //ADC値をdutyに入力 -50は補正値

        //CCP3のdutycycle変更(LEDの明るさが変化する)
        //解像度10ビットのうち上位8ビットをCCPR3Lレジスタに格納
        CCPR3L = dutycycle >> 2;
        //解像度10ビットのうち下位2ビットをCCP3CONレジスタの4,5ビットへ格納
        CCP3CON |= (dutycycle & 0x0003) << 4;

        //duty値のLCD表示
        itostring(4, dutycycle, s_dutycycle); //数値の文字列への変換
        LCD_posyx(0,12); // 1行9文字目にカーソル移動
        LCD_str(s_dutycycle);

        duty = (dutycycle +5) / 10; //+5は四捨五入処理
        itostring(3, duty, s_duty); //数値の文字列への変換
        LCD_posyx(1,8); // 2行8文字目にカーソル移動
        LCD_str(s_duty); //duty%値の表示
        LCD_posyx(1,11); // 2行11文字目にカーソル移動
        LCD_ROMstr("%");
    }
}

/***************************************
* int整数からASCII文字に変換
****************************************/
void itostring(char digit, unsigned int data, char *buffer) {
    char i;

    buffer += digit;		     // 最後の数字位置
    *buffer = 0;                     //文字列終端
    for(i=digit; i>0; i--) {	     // 変換は下位から上位へ
        buffer--;		     // ポインター1
        *buffer = (data % 10) + '0'; // ASCIIへ
        data = data / 10;	     // 次の桁へ
    }
}

//引数のアナロポートのA2D変換(10bit仕様) 2014/1/2
//PICC v9.81のsamplesフォルダ内のa2demo.cのプログラムを参考にアレンジ
unsigned int read_a2d(unsigned char channel) {
    channel &= 0b00011111; //truncate channel to 5 bits
    ADCON0 &= 0b10000011; //clear current channel select
    ADCON0 |= (channel << 2); //apply the new channel select
    __delay_us(5); // アナログ変換情報が設定されるまで5μ秒待つ
    ADCON0bits.GO_nDONE = 1; // initiate conversion on the selected channel
    while (ADCON0bits.GO_nDONE) continue;

    return (ADRESH << 8) | ADRESL;
}

//待ち時間が変数設定できるarg_delay_ms()関数を定義
//(__delay_ms()は引数に変数設定が出来ない為)
void arg_delay_ms(unsigned int x) {
    while(x) {
        __delay_ms(1);
        x--;
    }
}

//-------- i2cで1byteデータを送信する -----------------------
//  以下の引数が必要
//  addr : Slaveのアドレス
//  cont : Slaveへ制御コード
//  data : 送信するデータ
//  NACKやBus衝突などの対応は行っていない
// -----------------------------------------------------------
void i2cByteWrite(char addr, char cont, char data){
    SSPCON2bits.SEN = 1;           // Start condition 開始
    while(SSPCON2bits.SEN);        // Start condition 確認
    i2cTxData(addr);               // アドレス送信
    i2cTxData(cont);               // 制御コード送信
    i2cTxData(data);               // データ送信
    SSP1IF = 0;                    // 終了フラグクリア
    SSPCON2bits.PEN = 1;           // Stop condition 開始
    while(SSPCON2bits.PEN);        // Stop condition 確認
}

//-------- SSPBUFに1文字保存し送信終了を待つ -----------------
void i2cTxData(char data){
    SSP1IF = 0;                    // 終了フラグクリア
    SSPBUF = data;                 // データセット
    while(!SSP1IF);                // 送信終了待ち
}

//-------- 1文字表示 --------------------------------------
void LCD_dat(char chr){
    i2cByteWrite(0xA0, 0x80, chr);
    __delay_us(60);                // 60μsec
}
//-------- コマンド出力 --------------------------------------
void LCD_cmd(char cmd){
    i2cByteWrite(0xA0, 0x00, cmd);
    if(cmd & 0xFC)                 // 上位6ビットに1がある命令
        __delay_us(60);            // 60usec
    else
        __delay_ms(3);             // 3msec ClearおよびHomeコマンド
}
//-------- 全消去 ------------------------------------------------
void LCD_clr(void){
    LCD_cmd(0x01);                 //Clearコマンド出力
}
//-------- カーソル位置指定 --------------------------------------
void LCD_posyx(char ypos, char xpos){
    unsigned char pcode;
    switch(ypos & 0x03){           // 縦位置を取得
        case 0: pcode=0x80;break;  // 1行目
        case 1: pcode=0xC0;break;  // 2行目
        case 2: pcode=0x94;break;  // 3行目
        case 3: pcode=0xD4;break;  // 4行目
    }
    LCD_cmd(pcode += xpos);        // 横位置を加える
}
//-------- 文字列出力 -----------------------------------------
void LCD_str(char *str){
    while(*str)                    //文字列の終わり(00)まで継続
        LCD_dat(*str++);           //文字出力しポインタ+1
}
//-------- Rom 文字列出力 ------------------------------------
void LCD_ROMstr(const char *str){
    while(*str)                    //文字列の終わり(00)まで継続
        LCD_dat(*str++);           //文字出力しポインタ+1
}
//-------- 16進文字変換表示 --------------------------------
void LCD_hex(char c){
    const char hexch[] ="0123456789ABCDEF";
    LCD_dat(hexch[c >> 4]);        //上位4bit表示
    LCD_dat(hexch[c & 0xF]);       //下位4bit表示
}

//-------- 初期化 --------------------------------------
void LCD_int(void){
    __delay_ms(100);               // 電源安定するまでの時間
    LCD_cmd(0x38);                 // 8bit 2行 表示命令モード
    LCD_cmd(0x0C);                 // Display on Cursor=0 Blink=0
    LCD_cmd(0x06);                 // Entry Inc/Dec=1 Shift=0
    LCD_cmd(0x01);                 // Clear Display
}

★この情報は役に立ちましたか?

選択肢 投票
はい 53  
普通 51  
いいえ 52