トピック関連記事
48時間以内の記事は で表示されます
Duty比を変えるプログラム
以下のプログラムでLEDが暗くなる、明るくなるを繰り返すと思ったのですが、
点灯したままに見えます。
何処が悪いのでしょうか?
dutyを変える数値の50と1000はいい加減です。
動作確認したかったので、適当な数値です。
// TMR2レジスタをクリア
TMR2 = 0;
// タイマ2起動
T2CONbits.TMR2ON= 1;
// LEDをPWM制御
// デューテー比は10%100%の制御にする
while(1) {
// 5% -> 100%の制御
for(duty=50; duty<=1000; duty++) {
CCPR1L = duty / 4; // 上位8ビット
CCP1CONbits.CCP1X=duty;// CCP1Xビット
CCP1CONbits.CCP1Y=duty;// CCP1Yビット
__delay_ms(100);
}
// 100% -> 5%の制御
for(duty=1000; duty>=50; duty--) {
CCPR1L = duty / 4; // 上位8ビット
CCP1CONbits.CCP1X=duty;// CCP1Xビット
CCP1CONbits.CCP1Y=duty;// CCP1Yビット
__delay_ms(100);
}
}
点灯したままに見えます。
何処が悪いのでしょうか?
dutyを変える数値の50と1000はいい加減です。
動作確認したかったので、適当な数値です。
// TMR2レジスタをクリア
TMR2 = 0;
// タイマ2起動
T2CONbits.TMR2ON= 1;
// LEDをPWM制御
// デューテー比は10%100%の制御にする
while(1) {
// 5% -> 100%の制御
for(duty=50; duty<=1000; duty++) {
CCPR1L = duty / 4; // 上位8ビット
CCP1CONbits.CCP1X=duty;// CCP1Xビット
CCP1CONbits.CCP1Y=duty;// CCP1Yビット
__delay_ms(100);
}
// 100% -> 5%の制御
for(duty=1000; duty>=50; duty--) {
CCPR1L = duty / 4; // 上位8ビット
CCP1CONbits.CCP1X=duty;// CCP1Xビット
CCP1CONbits.CCP1Y=duty;// CCP1Yビット
__delay_ms(100);
}
}
Re: Duty比を変えるプログラム
上手くいきました。
動作しなかった理由が分かりました。
それは、Configでした。
色々と調べたので、関数の使い方など、ちょっとは分かるようになりました。
// PIC16F88 Configuration Bit Settings
// 'C' source line config statements
// CONFIG1
#pragma config FOSC = INTOSCIO // Oscillator Selection bits (INTRC oscillator; port I/O function on both RA6/OSC2/CLKO pin and RA7/OSC1/CLKI pin)
#pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = ON // RA5/MCLR/VPP Pin Function Select bit (RA5/MCLR/VPP pin function is MCLR)
#pragma config BOREN = OFF // Brown-out Reset Enable bit (BOR disabled)
#pragma config LVP = OFF // Low-Voltage Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming)
#pragma config CPD = OFF // Data EE Memory Code Protection bit (Code protection off)
#pragma config WRT = OFF // Flash Program Memory Write Enable bits (Write protection off)
#pragma config CCPMX = RB3 // CCP1 Pin Selection bit (CCP1 function on RB3)
#pragma config CP = OFF // Flash Program Memory Code Protection bit (Code protection off)
// CONFIG2
#pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enable bit (Fail-Safe Clock Monitor enabled)
#pragma config IESO = OFF // Internal External Switchover bit (Internal External Switchover mode enabled)
// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.
#include <xc.h>
// クロック周波数指定
// (__delay_ms()関数が必要としているため)
#define _XTAL_FREQ 1000000
// プロトタイプ宣言
void InitPWM (void);
void InitTimer2 (void);
// メイン関数
void main (void)
{
// 1,2,17,18端子を入出力端子に設定
CMCON = 0x07;
// 電圧レベルの初期設定
PORTA = 0xFF;
PORTB = 0xFF;
// 入出力設定
TRISA = 0x20;
TRISB = 0x00;
OSCCON = 0x40; //クロック周波数を1MHzに設定
ANSEL = 0x00; //すべてのピンをデジタルモードに設定
// PWMモード設定関数の呼び出し
InitPWM();
// タイマ2設定関数の呼び出し
InitTimer2();
unsigned short duty;// PWMのデューティーサイクル
while(1){
// 5% -> 100%の制御
for(duty=50; duty<=1000;++duty) {
CCPR1L = duty / 4; // 上位8ビット
CCP1CONbits.CCP1X=duty;// CCP1Xビット
CCP1CONbits.CCP1Y=duty;// CCP1Yビット
__delay_ms(10);
}
// 100% -> 5%の制御
for(duty=1000; duty>=50; duty--) {
CCPR1L = duty / 4; // 上位8ビット
CCP1CONbits.CCP1X=duty;// CCP1Xビット
CCP1CONbits.CCP1Y=duty;// CCP1Yビット
__delay_ms(10);
}
}
}
// PWMモード設定関数
void InitPWM (void)
{
// RB3端子を出力端子に設定
TRISBbits.TRISB3 = 0;
// CCPのモードをPWMモードに設定
CCP1CONbits.CCP1M3=1;
CCP1CONbits.CCP1M2=1;
CCP1CONbits.CCP1M1=0;
CCP1CONbits.CCP1M0=0;
// 周期を1μ秒に設定(249 + 1μ秒)
PR2 =249;
// デューティーサイクルを0.5ms
CCPR1L = 500/4;
CCP1CONbits.CCP1X=0;
CCP1CONbits.CCP1Y=0;
}
// タイマ2設定関数
void InitTimer2 (void)
{
// プリスケーラ値を1に設定
T2CONbits.T2CKPS1=0;
T2CONbits.T2CKPS0=0;
// TMR2レジスタをクリア
TMR2 = 0;
// タイマ2起動
T2CONbits.TMR2ON= 1;
}
動作しなかった理由が分かりました。
それは、Configでした。
色々と調べたので、関数の使い方など、ちょっとは分かるようになりました。
// PIC16F88 Configuration Bit Settings
// 'C' source line config statements
// CONFIG1
#pragma config FOSC = INTOSCIO // Oscillator Selection bits (INTRC oscillator; port I/O function on both RA6/OSC2/CLKO pin and RA7/OSC1/CLKI pin)
#pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = ON // RA5/MCLR/VPP Pin Function Select bit (RA5/MCLR/VPP pin function is MCLR)
#pragma config BOREN = OFF // Brown-out Reset Enable bit (BOR disabled)
#pragma config LVP = OFF // Low-Voltage Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming)
#pragma config CPD = OFF // Data EE Memory Code Protection bit (Code protection off)
#pragma config WRT = OFF // Flash Program Memory Write Enable bits (Write protection off)
#pragma config CCPMX = RB3 // CCP1 Pin Selection bit (CCP1 function on RB3)
#pragma config CP = OFF // Flash Program Memory Code Protection bit (Code protection off)
// CONFIG2
#pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enable bit (Fail-Safe Clock Monitor enabled)
#pragma config IESO = OFF // Internal External Switchover bit (Internal External Switchover mode enabled)
// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.
#include <xc.h>
// クロック周波数指定
// (__delay_ms()関数が必要としているため)
#define _XTAL_FREQ 1000000
// プロトタイプ宣言
void InitPWM (void);
void InitTimer2 (void);
// メイン関数
void main (void)
{
// 1,2,17,18端子を入出力端子に設定
CMCON = 0x07;
// 電圧レベルの初期設定
PORTA = 0xFF;
PORTB = 0xFF;
// 入出力設定
TRISA = 0x20;
TRISB = 0x00;
OSCCON = 0x40; //クロック周波数を1MHzに設定
ANSEL = 0x00; //すべてのピンをデジタルモードに設定
// PWMモード設定関数の呼び出し
InitPWM();
// タイマ2設定関数の呼び出し
InitTimer2();
unsigned short duty;// PWMのデューティーサイクル
while(1){
// 5% -> 100%の制御
for(duty=50; duty<=1000;++duty) {
CCPR1L = duty / 4; // 上位8ビット
CCP1CONbits.CCP1X=duty;// CCP1Xビット
CCP1CONbits.CCP1Y=duty;// CCP1Yビット
__delay_ms(10);
}
// 100% -> 5%の制御
for(duty=1000; duty>=50; duty--) {
CCPR1L = duty / 4; // 上位8ビット
CCP1CONbits.CCP1X=duty;// CCP1Xビット
CCP1CONbits.CCP1Y=duty;// CCP1Yビット
__delay_ms(10);
}
}
}
// PWMモード設定関数
void InitPWM (void)
{
// RB3端子を出力端子に設定
TRISBbits.TRISB3 = 0;
// CCPのモードをPWMモードに設定
CCP1CONbits.CCP1M3=1;
CCP1CONbits.CCP1M2=1;
CCP1CONbits.CCP1M1=0;
CCP1CONbits.CCP1M0=0;
// 周期を1μ秒に設定(249 + 1μ秒)
PR2 =249;
// デューティーサイクルを0.5ms
CCPR1L = 500/4;
CCP1CONbits.CCP1X=0;
CCP1CONbits.CCP1Y=0;
}
// タイマ2設定関数
void InitTimer2 (void)
{
// プリスケーラ値を1に設定
T2CONbits.T2CKPS1=0;
T2CONbits.T2CKPS0=0;
// TMR2レジスタをクリア
TMR2 = 0;
// タイマ2起動
T2CONbits.TMR2ON= 1;
}
Re: Duty比を変えるプログラム
TRさん,猛牛ロックさん,こんばんは。
TRさん,頑張ってますね。
PWMモード復習してみました。
TRさんの書かれたプログラムですが,
for(duty=50; duty<=1000;++duty) {
CCPR1L = duty / 4; // 上位8ビット
CCP1CONbits.CCP1X=duty;// CCP1Xビット
CCP1CONbits.CCP1Y=duty;// CCP1Yビット
__delay_ms(10);
}
の
CCP1CONbits.CCP1X=duty;// CCP1Xビット
CCP1CONbits.CCP1Y=duty;// CCP1Yビッ
部分ですが,ビットの操作なので,0か1がはいるのですが,
10進数を代入するとどうなるのでしょうね。
ちゃんと,下位の1ビット目と2ビットめがそれぞれ入る
のでしょうか。
ちょっと分からないところです。
もしかして,
CCP1CONbits.CCP1X=((duty>>1)&1);// dutyの1ビット目代入
CCP1CONbits.CCP1Y=(duty&1);// dutyの0ビット目を代入
みたいにしないとだめかもしれません。
TRさん,頑張ってますね。
PWMモード復習してみました。
TRさんの書かれたプログラムですが,
for(duty=50; duty<=1000;++duty) {
CCPR1L = duty / 4; // 上位8ビット
CCP1CONbits.CCP1X=duty;// CCP1Xビット
CCP1CONbits.CCP1Y=duty;// CCP1Yビット
__delay_ms(10);
}
の
CCP1CONbits.CCP1X=duty;// CCP1Xビット
CCP1CONbits.CCP1Y=duty;// CCP1Yビッ
部分ですが,ビットの操作なので,0か1がはいるのですが,
10進数を代入するとどうなるのでしょうね。
ちゃんと,下位の1ビット目と2ビットめがそれぞれ入る
のでしょうか。
ちょっと分からないところです。
もしかして,
CCP1CONbits.CCP1X=((duty>>1)&1);// dutyの1ビット目代入
CCP1CONbits.CCP1Y=(duty&1);// dutyの0ビット目を代入
みたいにしないとだめかもしれません。
mabo 2018/11/13(Tue) 00:22 No.1199
Re: Duty比を変えるプログラム
maboさん、レス有難うございます。
私も、10進数を=にしてよいものかと感じていますが、
ツールラボさんの解説を貼り付けます。
さて、500をわざわざ2進数に変換して、その上位8ビットや下位2ビットを求めるのは面倒ですので、楽な方法でプログラムを書くことにしましょう。
まず、上位8ビットの求め方です。2進数表現では、2で割ると1桁右に移動します。一番右の桁は無くなります。
Pic app 4 binary calculation
さらに2で割ればもう1桁右に移動します。ということは、500を4で割れば上位8ビットを取り出すことができます。
ということで、CCPR1Lに上位8ビットを設定するには、
CCPR1L = 500/4;
と書けばよいことになります。
私も、10進数を=にしてよいものかと感じていますが、
ツールラボさんの解説を貼り付けます。
さて、500をわざわざ2進数に変換して、その上位8ビットや下位2ビットを求めるのは面倒ですので、楽な方法でプログラムを書くことにしましょう。
まず、上位8ビットの求め方です。2進数表現では、2で割ると1桁右に移動します。一番右の桁は無くなります。
Pic app 4 binary calculation
さらに2で割ればもう1桁右に移動します。ということは、500を4で割れば上位8ビットを取り出すことができます。
ということで、CCPR1Lに上位8ビットを設定するには、
CCPR1L = 500/4;
と書けばよいことになります。
Re: Duty比を変えるプログラム
TRさん,猛牛ロックさん,おはようございます。
>上位8ビット
を取り出すにには,右に,2ビット分シフトですから,
意味的には,4で割ることと同意ですよね。
このへんの操作が面倒ですよね。
下位ビットの設定には,
CCP1CONbits.DC1B
がTRさんのおっしゃるツールラボでは使われてましたね。
CCP1CONbits.DC1B = 500
あるいは,
CCP1CONbits.DC1B = 500 && 0b11;
のように書いてありました。
CCP1CONbits.DC1B
だと,
CCP1CONbits.CCP1X
CCP1CONbits.CCP1Y
を使わなくても一度ですむみたいですね。
PWMはすっかり忘れていました。
>上位8ビット
を取り出すにには,右に,2ビット分シフトですから,
意味的には,4で割ることと同意ですよね。
このへんの操作が面倒ですよね。
下位ビットの設定には,
CCP1CONbits.DC1B
がTRさんのおっしゃるツールラボでは使われてましたね。
CCP1CONbits.DC1B = 500
あるいは,
CCP1CONbits.DC1B = 500 && 0b11;
のように書いてありました。
CCP1CONbits.DC1B
だと,
CCP1CONbits.CCP1X
CCP1CONbits.CCP1Y
を使わなくても一度ですむみたいですね。
PWMはすっかり忘れていました。
mabo 2018/11/13(Tue) 08:46 No.1201
Re: Duty比を変えるプログラム
10進数をレジスタに=にしてもOKみたいですね!
CCP1CONbits.DC1B 
これですが、16F88の場合、無いようでしたので、1バイトづつとじました。
本当に忘れるほうが早い (笑)
CCP1CONbits.DC1B 
これですが、16F88の場合、無いようでしたので、1バイトづつとじました。
本当に忘れるほうが早い (笑)
TR 2018/11/13(Tue) 10:49 No.1202
Re: Duty比を変えるプログラム
ツールラボの話は別のマイコンの話です。
CCP1CONbits.DC1Bは2bitの器です。
なので、4で割った余りが入ります。
CCP1CONbits.CCP1X=500;
CCP1CONbits.CCP1Y=500;
なら、当然、両方とも0です。
1bitの器(が2つ)しかない所にそれよりも多い数を入れると、繰り上がった分は消えます。
簡単に言えば2で割った余りです。
duty比が1なら判るでしょう?
CCP1CONbits.CCP1X=1;
CCP1CONbits.CCP1Y=1;
と書いて、Xの方が0になる筈ないですよね?
MABOさんの言う通りの処理が必要です。
まぁ、端数なので気付かない可能性が大きいですけど。
…と思ったら
> CCP1CONbits.DC1B = 500 && 0b11;
これは駄目です。そのサイトに書いてあったんですか?
これでは500の部分が0以外なら、CCP1CONbits.DC1Bには0b01が入ります。
0の場合は0です。
(本当は「&&」では無く「&」)
CCP1CONbits.DC1Bは2bitの器です。
なので、4で割った余りが入ります。
CCP1CONbits.CCP1X=500;
CCP1CONbits.CCP1Y=500;
なら、当然、両方とも0です。
1bitの器(が2つ)しかない所にそれよりも多い数を入れると、繰り上がった分は消えます。
簡単に言えば2で割った余りです。
duty比が1なら判るでしょう?
CCP1CONbits.CCP1X=1;
CCP1CONbits.CCP1Y=1;
と書いて、Xの方が0になる筈ないですよね?
MABOさんの言う通りの処理が必要です。
まぁ、端数なので気付かない可能性が大きいですけど。
…と思ったら
> CCP1CONbits.DC1B = 500 && 0b11;
これは駄目です。そのサイトに書いてあったんですか?
これでは500の部分が0以外なら、CCP1CONbits.DC1Bには0b01が入ります。
0の場合は0です。
(本当は「&&」では無く「&」)
猛牛ロック 2018/11/14(Wed) 03:37 No.1203
Re: Duty比を変えるプログラム
猛牛ロックさんへ
>簡単に言えば2で割った余りです。
なんだろうと思って、検索したら、 2で割った、余りの1を下から並べると、
2進数表現になるとありました。
でも、10進数に対応する2進数の上位8ビットを取り出すために
10進数÷4 とすればOKというプログラムは、、、
何か不思議な感じです。
オシログラフで確認できたらいいのでしょうけど、自分のレベルでは持っていません。
ただ、実験してみると、次第に明るくなって、次第に暗くなりました。
・10進数÷4 とすればOKというプログラム
CCPR1L = 500/4;
・参考したURL
https://arigato-lucky.at.webry.info/200710/article_17.html
※
今回も、一つ覚えたので、良かったです。
でなんですが、
PWM機能を使うために、ADRESというレジスタ
があるようなのですが、
これは、16F88にはあるのでしょうか?
自分としては見つかりませんでした。
良かったら、教えて下さい。
>簡単に言えば2で割った余りです。
なんだろうと思って、検索したら、 2で割った、余りの1を下から並べると、
2進数表現になるとありました。
でも、10進数に対応する2進数の上位8ビットを取り出すために
10進数÷4 とすればOKというプログラムは、、、
何か不思議な感じです。
オシログラフで確認できたらいいのでしょうけど、自分のレベルでは持っていません。
ただ、実験してみると、次第に明るくなって、次第に暗くなりました。
・10進数÷4 とすればOKというプログラム
CCPR1L = 500/4;
・参考したURL
https://arigato-lucky.at.webry.info/200710/article_17.html
※
今回も、一つ覚えたので、良かったです。
でなんですが、
PWM機能を使うために、ADRESというレジスタ
があるようなのですが、
これは、16F88にはあるのでしょうか?
自分としては見つかりませんでした。
良かったら、教えて下さい。
Re: Duty比を変えるプログラム
10進数、2進数、16進数などは単に人が識別するためのものです。
値としてはどれも同じです。
2進数「表現」とあるように、人にとって意味がある区別の仕方です。
> 10進数÷4 とすればOKというプログラムは、、、
10進数は隣の位が10倍、或いは1/10です。2進数の隣の位は同じ様に2倍、或いは1/2です。
○進数は○で、位が上がる、と言う事です。
> 実験してみると、次第に明るくなって、次第に暗くなりました。
10桁ある中で、下2桁ですから、ほとんど感じないでしょうね。
確認するならレジスタを読み込めば判りますよ。
> 自分としては見つかりませんでした。
検索すればすぐ判りますよ。
値としてはどれも同じです。
2進数「表現」とあるように、人にとって意味がある区別の仕方です。
> 10進数÷4 とすればOKというプログラムは、、、
10進数は隣の位が10倍、或いは1/10です。2進数の隣の位は同じ様に2倍、或いは1/2です。
○進数は○で、位が上がる、と言う事です。
> 実験してみると、次第に明るくなって、次第に暗くなりました。
10桁ある中で、下2桁ですから、ほとんど感じないでしょうね。
確認するならレジスタを読み込めば判りますよ。
> 自分としては見つかりませんでした。
検索すればすぐ判りますよ。
猛牛ロック 2018/11/14(Wed) 21:25 No.1205
Re: Duty比を変えるプログラム
TRさん,猛牛ロックさん,こんばんは。
>CCP1CONbits.DC1B = 500 && 0b11;
マスク処理ですから,猛牛ロックさんのおっしゃるように,
&一つですね。
HPに書いてある記事は,なんの疑いもなく信じてしまうところがあるので,
気をつけないとだめですね。
https://tool-lab.com/make/pic-app-4/
2進数→←10進数の変換をよくエクセルを使ってやります。
ただ,今までは,小さな数でしたので,問題なくできましたが,
512だと備え付けの関数ではだめでした。
=DEC2BIN(N,n)
という関数ですが,
−513<N<512
1<=n<11
でした。符号も絡んでくるので,ちょっと頭痛くなります。
>CCP1CONbits.DC1B = 500 && 0b11;
マスク処理ですから,猛牛ロックさんのおっしゃるように,
&一つですね。
HPに書いてある記事は,なんの疑いもなく信じてしまうところがあるので,
気をつけないとだめですね。
https://tool-lab.com/make/pic-app-4/
2進数→←10進数の変換をよくエクセルを使ってやります。
ただ,今までは,小さな数でしたので,問題なくできましたが,
512だと備え付けの関数ではだめでした。
=DEC2BIN(N,n)
という関数ですが,
−513<N<512
1<=n<11
でした。符号も絡んでくるので,ちょっと頭痛くなります。
mabo 2018/11/15(Thu) 00:08 No.1206
Re: Duty比を変えるプログラム
ADRESレジスターですが、
最初、ADRESで検索しても無かったので、
次に「A/D Result register」でも検索しましたが、
ADRESの表記は見当たりませんでした。
というのも、MPLAB IDEにADRESと書き込むと
エラーを起こしたので、
16F88の場合は、レジスターの名称が違うと思ったので、
探し始めました。
ADRESH、とADRESLの表記はあるのですが、
ADRESに対応する16F88版レジスターが見つかりません。
maboさん
2進数変換ですが、自分は下記サイトを利用しています。
https://hogehoge.tk/tool/number.html
最初、ADRESで検索しても無かったので、
次に「A/D Result register」でも検索しましたが、
ADRESの表記は見当たりませんでした。
というのも、MPLAB IDEにADRESと書き込むと
エラーを起こしたので、
16F88の場合は、レジスターの名称が違うと思ったので、
探し始めました。
ADRESH、とADRESLの表記はあるのですが、
ADRESに対応する16F88版レジスターが見つかりません。
maboさん
2進数変換ですが、自分は下記サイトを利用しています。
https://hogehoge.tk/tool/number.html
Re: Duty比を変えるプログラム
TRさん,猛牛ロックさんおはようございます。
TRさん,2進数変換のHP紹介ありがとうございます。
>ADRESレジスターですが、
データシート見てみると,A/D変換の結果の格納で使われてるようですね。
ADRESH
ADRESL
の記述がデータしとの下の方にありました。
A/D変換の結果の格納に使うみたいですね。
http://physics.cocolog-nifty.com/weblog/2012/07/post-2147.html
にプログラムでてます。
TRさん,2進数変換のHP紹介ありがとうございます。
>ADRESレジスターですが、
データシート見てみると,A/D変換の結果の格納で使われてるようですね。
ADRESH
ADRESL
の記述がデータしとの下の方にありました。
A/D変換の結果の格納に使うみたいですね。
http://physics.cocolog-nifty.com/weblog/2012/07/post-2147.html
にプログラムでてます。
mabo 2018/11/15(Thu) 09:13 No.1208
Re: Duty比を変えるプログラム
maboさん有り難うございます
やはり、F88にはADRESレジスタが無かったようですね。
紹介先の管理人は、対処として、
unsigned int adconv() 関数を作っています。
でも、プログラムで
return (ADRESH<<8) + ADRESL
このように、+として10バイトを取り出せるのは、驚きました!?
16F88は面倒くさい。
もっと簡単なPICが欲しいです
やはり、F88にはADRESレジスタが無かったようですね。
紹介先の管理人は、対処として、
unsigned int adconv() 関数を作っています。
でも、プログラムで
return (ADRESH<<8) + ADRESL
このように、+として10バイトを取り出せるのは、驚きました!?
16F88は面倒くさい。
もっと簡単なPICが欲しいです
TR 2018/11/15(Thu) 13:42 No.1209
Re: Duty比を変えるプログラム
maboさん、こんばんは。
ご紹介くださった、頁のLチカを早速検証しました。
IDXの今バージョンに変更し、
「<」を半角にしたら、動作しました。
で、以下のプログラムですが、
今までと、ちと違う書き方をしています。
For文です。
{}内に、今までは、処理する内容を書いてきましたが、
空欄の場合は、単に++の足し算をするだけ、
つまり、時間を稼ぐだけのことになるのでしょうか?
http://physics.cocolog-nifty.com/weblog/2012/07/post-2147.html
RB3 = 1;
for(i = 0; i<tmp; i++){};
__delay_ms(2);
RB3 = 0;
for(i = 0; i<tmp; i++){};
__delay_ms(2);
}
ご紹介くださった、頁のLチカを早速検証しました。
IDXの今バージョンに変更し、
「<」を半角にしたら、動作しました。
で、以下のプログラムですが、
今までと、ちと違う書き方をしています。
For文です。
{}内に、今までは、処理する内容を書いてきましたが、
空欄の場合は、単に++の足し算をするだけ、
つまり、時間を稼ぐだけのことになるのでしょうか?
http://physics.cocolog-nifty.com/weblog/2012/07/post-2147.html
RB3 = 1;
for(i = 0; i<tmp; i++){};
__delay_ms(2);
RB3 = 0;
for(i = 0; i<tmp; i++){};
__delay_ms(2);
}
Re: Duty比を変えるプログラム
TRさん,こんばんは。
>空欄の場合は、単に++の足し算をするだけ、
>つまり、時間を稼ぐだけのことになるのでしょうか?
そうだと思います。
意味的には,
__delay_ms();
と同じような処理をすることになると思いますが,
確か,__delay_ms() では,括弧の中に変数は入れられなかった,ような気がします。
それで,こんな風にしたのかなと思います。
変数が入れられれば __delay_ms() 使えばいいのでしょうけど。
>空欄の場合は、単に++の足し算をするだけ、
>つまり、時間を稼ぐだけのことになるのでしょうか?
そうだと思います。
意味的には,
__delay_ms();
と同じような処理をすることになると思いますが,
確か,__delay_ms() では,括弧の中に変数は入れられなかった,ような気がします。
それで,こんな風にしたのかなと思います。
変数が入れられれば __delay_ms() 使えばいいのでしょうけど。
mabo 2018/11/15(Thu) 23:39 No.1211
Re: Duty比を変えるプログラム
> F88にはADRESレジスタが無かったようですね。
え?まぁ、無いとも言えますけど、あるとも言えます。
ADRESHとADRESLがADRESです。
10ビット性能のADCなので、必然的に2つに分かれます。
> 16F88は面倒くさい。
いやいや、16F88は使いやすさで生き残っているマイコンですよ。
ウィンドウズで言えばXPみたいなものかなぁ。
最近のものは覚えることが2〜3倍程度あります。16F19155のデータシートなんて735ページまであります。
頭に来るのは、それ以外にエラッタのデータシートがあったり、データシートのバージョンで重要な事項が
載っていなかったりすることです。
RB3 = 1;
for(i = 0; i<tmp; i++){};
__delay_ms(2);
RB3 = 0;
for(i = 0; i<tmp; i++){};
__delay_ms(2);
}
はあまり参考にしない方が良いです。
動かしてみないとどうなるか判らないコードです。
本人も判っていなかったのでは?
やりたかったのは
while (1){
tmp = adconv();
RB3 = 1;
__delay_ms(tmp);
RB3 = 0;
__delay_ms(tmp);
}
のような事だと思いますけど、
(__delay_ms()の引数に変数を入れては駄目ですけど)
for(i = 0; i<tmp; i++){}
の部分は
volatile unsigned int i;
とiを宣言していないと省略される場合があります。
※内容が{}と空だからです。
そして、その次の
;
は単独です。for文とは関係ありません。
そして、
__delay_ms(2);
も単独です。
つまり、3つの何もしない命令を並べています。
通常は
RB3 = 1;
for(i = 0; i<tmp; i++)__delay_ms(1);
RB3 = 0;
for(i = 0; i<tmp; i++)__delay_ms(1);
です。
え?まぁ、無いとも言えますけど、あるとも言えます。
ADRESHとADRESLがADRESです。
10ビット性能のADCなので、必然的に2つに分かれます。
> 16F88は面倒くさい。
いやいや、16F88は使いやすさで生き残っているマイコンですよ。
ウィンドウズで言えばXPみたいなものかなぁ。
最近のものは覚えることが2〜3倍程度あります。16F19155のデータシートなんて735ページまであります。
頭に来るのは、それ以外にエラッタのデータシートがあったり、データシートのバージョンで重要な事項が
載っていなかったりすることです。
RB3 = 1;
for(i = 0; i<tmp; i++){};
__delay_ms(2);
RB3 = 0;
for(i = 0; i<tmp; i++){};
__delay_ms(2);
}
はあまり参考にしない方が良いです。
動かしてみないとどうなるか判らないコードです。
本人も判っていなかったのでは?
やりたかったのは
while (1){
tmp = adconv();
RB3 = 1;
__delay_ms(tmp);
RB3 = 0;
__delay_ms(tmp);
}
のような事だと思いますけど、
(__delay_ms()の引数に変数を入れては駄目ですけど)
for(i = 0; i<tmp; i++){}
の部分は
volatile unsigned int i;
とiを宣言していないと省略される場合があります。
※内容が{}と空だからです。
そして、その次の
;
は単独です。for文とは関係ありません。
そして、
__delay_ms(2);
も単独です。
つまり、3つの何もしない命令を並べています。
通常は
RB3 = 1;
for(i = 0; i<tmp; i++)__delay_ms(1);
RB3 = 0;
for(i = 0; i<tmp; i++)__delay_ms(1);
です。
猛牛ロック 2018/11/17(Sat) 00:22 No.1212
Re: Duty比を変えるプログラム
因みに、そのサイトのプログラムをArduinoでやると
void setup() {
pinMode(13,OUTPUT);
}
void loop() {
word tmp=analogRead(A0)/4;
digitalWrite(13,HIGH);
delay(tmp);
digitalWrite(13,LOW);
delay(tmp);
}
だけです。データシートを見る必要はありません。
初心者はリファレンスのページは見る必要あるでしょうけど。
回路もLEDは13番ピンに付いているので、
ボリュームの配線だけ5V、A0ピン、GNDと繋げば直ぐに書き込んで試せます。
そう言えば、そのサイトの人も、今はArduinoに鞍替えした?のかも知れません。
http://physics.cocolog-nifty.com/weblog/2018/06/arduino14-392d.html
マルチボートも試していたようです。
ついでに、ボリュームに合わせて明るさを変えるスケッチだと更に簡単です。
void setup() {
}
void loop() {
analogWrite(3,analogRead(A0)/4);
delay(10);
}
3番ピン-LED、A0ピン-ボリュームです。
void setup() {
pinMode(13,OUTPUT);
}
void loop() {
word tmp=analogRead(A0)/4;
digitalWrite(13,HIGH);
delay(tmp);
digitalWrite(13,LOW);
delay(tmp);
}
だけです。データシートを見る必要はありません。
初心者はリファレンスのページは見る必要あるでしょうけど。
回路もLEDは13番ピンに付いているので、
ボリュームの配線だけ5V、A0ピン、GNDと繋げば直ぐに書き込んで試せます。
そう言えば、そのサイトの人も、今はArduinoに鞍替えした?のかも知れません。
http://physics.cocolog-nifty.com/weblog/2018/06/arduino14-392d.html
マルチボートも試していたようです。
ついでに、ボリュームに合わせて明るさを変えるスケッチだと更に簡単です。
void setup() {
}
void loop() {
analogWrite(3,analogRead(A0)/4);
delay(10);
}
3番ピン-LED、A0ピン-ボリュームです。
猛牛ロック 2018/11/17(Sat) 00:43 No.1213
Re: Duty比を変えるプログラム
TRさん,猛牛ロックさん,こんにちは。
猛牛ロックさん,いろいろありがとうございます。
私もちょっとだけ,Arduinoいじりましたが,
PICに比べると親切過ぎる感じですね。
それから,
analogRead(A0)/4
ですが,たんに,4で割るのか,それとも上位の4ビットを
とりだすのでしょうか。
この辺の仕様がちょっと分からないかなと思います。
猛牛ロックさん,いろいろありがとうございます。
私もちょっとだけ,Arduinoいじりましたが,
PICに比べると親切過ぎる感じですね。
それから,
analogRead(A0)/4
ですが,たんに,4で割るのか,それとも上位の4ビットを
とりだすのでしょうか。
この辺の仕様がちょっと分からないかなと思います。
mabo 2018/11/17(Sat) 12:28 No.1214
Re: Duty比を変えるプログラム
> たんに,4で割るのか,それとも上位の4ビットを
> とりだすのでしょうか。
単に4で割っています。元が10ビットなので、上位8ビットを取り出しています。
※analogWriteは8ビット指定、analogReadは10ビット読出し
> とりだすのでしょうか。
単に4で割っています。元が10ビットなので、上位8ビットを取り出しています。
※analogWriteは8ビット指定、analogReadは10ビット読出し
猛牛ロック 2018/11/17(Sat) 12:42 No.1215
Re: Duty比を変えるプログラム
みなさんこんばんは。
ADRESですが、
ようやく分かりました。
やはりレジスタとしては存在していないそうです。
でも、
12F1822には、ADRESとすれば、10ビットとして取り扱うことが出来るそうです。
PIC12F1822にはある機能ですが、88や627Aにはなさそうです。
PIC12F1822日本語バージョンのデータシート149頁上の4行目に
ADRES<9:2>と表記されています。
この独特の表記方法からすると、
9から2ビットまでをひとくくりにする、、、←自分的理解ですが。
それから、maboさんのご紹介下さったプログラムですが、
以下のように変えました。
動作しています。
気になった点は、
char str[7]; ← 配列、プログラムの何処にもないので不要。
RB3 = 1;
for(i = 0; i<tmp; i++){};
上の2行です。RB3を{}の中に入れました
後、猛牛ロックさんの言われるように ; も不要ですね。
話は戻りますが、この管理人さんも88を使っていますが、
12F1822にすれば、電圧読み取りの下記プログラム
記
return (ADRESH<<8) + ADRESL;
上記を
return(ADRES); と出来るはずです。
拘る理由
教科書では
return(○○)となっているからです。
本当に上記の記載方法で上位8ビットと下位2ビットがきちんと並んでいるのだろうかと??
変更後
// CONFIG1
#pragma config FOSC = INTOSCIO // Oscillator Selection bits (INTRC oscillator; port I/O function on both RA6/OSC2/CLKO pin and RA7/OSC1/CLKI pin)
#pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = ON // RA5/MCLR/VPP Pin Function Select bit (RA5/MCLR/VPP pin function is MCLR)
#pragma config BOREN = OFF // Brown-out Reset Enable bit (BOR disabled)
#pragma config LVP = OFF // Low-Voltage Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming)
#pragma config CPD = OFF // Data EE Memory Code Protection bit (Code protection off)
#pragma config WRT = OFF // Flash Program Memory Write Enable bits (Write protection off)
#pragma config CCPMX = RB3 // CCP1 Pin Selection bit (CCP1 function on RB3)
#pragma config CP = OFF // Flash Program Memory Code Protection bit (Code protection off)
// CONFIG2
#pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enable bit (Fail-Safe Clock Monitor enabled)
#pragma config IESO = OFF // Internal External Switchover bit (Internal External Switchover mode enabled)
// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.
#include <xc.h>
// クロック周波数指定
// (__delay_ms()関数が必要としているため)
#define _XTAL_FREQ 4000000
//プロトタイプ宣言
unsigned int adconv();
//変数宣言
unsigned int tmp;
unsigned int i;
void main()
{
OSCCON = 0b0110000; // 内蔵OSC 4MHz
// ADコンバータ設定
ADCON0 = 0b01000001; // RA0をADコンバータピンにし、ADコンバータ機能をEbableに
ADCON1 = 0b10000000; // 結果数値は右寄せ、基準電圧はVDD
ANSEL = 0b00000001; // RA0(AN0)はアナログで読み取りピン
TRISA = 0b00000001; // RA0(AN0)はアナログで読み取りピン(入力)
TRISB = 0x00; // すべて出力
PORTA = 0x00;
PORTB = 0x00;
while (1)
{
tmp = adconv();
for(i = 0; i<tmp; i++){RB3=1;}
__delay_ms(2);
for(i = 0; i<tmp; i++){RB3=0;};
__delay_ms(2);
}
}
unsigned int adconv()
{
__delay_us(20); //アクィジョン時間 20us
ADCON0bits.GO_DONE= 1; //AD変換開始
while(ADCON0bits.GO_DONE); //変換完了待ち
return (ADRESH<<8)+ ADRESL;
}
ADRESですが、
ようやく分かりました。
やはりレジスタとしては存在していないそうです。
でも、
12F1822には、ADRESとすれば、10ビットとして取り扱うことが出来るそうです。
PIC12F1822にはある機能ですが、88や627Aにはなさそうです。
PIC12F1822日本語バージョンのデータシート149頁上の4行目に
ADRES<9:2>と表記されています。
この独特の表記方法からすると、
9から2ビットまでをひとくくりにする、、、←自分的理解ですが。
それから、maboさんのご紹介下さったプログラムですが、
以下のように変えました。
動作しています。
気になった点は、
char str[7]; ← 配列、プログラムの何処にもないので不要。
RB3 = 1;
for(i = 0; i<tmp; i++){};
上の2行です。RB3を{}の中に入れました
後、猛牛ロックさんの言われるように ; も不要ですね。
話は戻りますが、この管理人さんも88を使っていますが、
12F1822にすれば、電圧読み取りの下記プログラム
記
return (ADRESH<<8) + ADRESL;
上記を
return(ADRES); と出来るはずです。
拘る理由
教科書では
return(○○)となっているからです。
本当に上記の記載方法で上位8ビットと下位2ビットがきちんと並んでいるのだろうかと??
変更後
// CONFIG1
#pragma config FOSC = INTOSCIO // Oscillator Selection bits (INTRC oscillator; port I/O function on both RA6/OSC2/CLKO pin and RA7/OSC1/CLKI pin)
#pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = ON // RA5/MCLR/VPP Pin Function Select bit (RA5/MCLR/VPP pin function is MCLR)
#pragma config BOREN = OFF // Brown-out Reset Enable bit (BOR disabled)
#pragma config LVP = OFF // Low-Voltage Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming)
#pragma config CPD = OFF // Data EE Memory Code Protection bit (Code protection off)
#pragma config WRT = OFF // Flash Program Memory Write Enable bits (Write protection off)
#pragma config CCPMX = RB3 // CCP1 Pin Selection bit (CCP1 function on RB3)
#pragma config CP = OFF // Flash Program Memory Code Protection bit (Code protection off)
// CONFIG2
#pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enable bit (Fail-Safe Clock Monitor enabled)
#pragma config IESO = OFF // Internal External Switchover bit (Internal External Switchover mode enabled)
// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.
#include <xc.h>
// クロック周波数指定
// (__delay_ms()関数が必要としているため)
#define _XTAL_FREQ 4000000
//プロトタイプ宣言
unsigned int adconv();
//変数宣言
unsigned int tmp;
unsigned int i;
void main()
{
OSCCON = 0b0110000; // 内蔵OSC 4MHz
// ADコンバータ設定
ADCON0 = 0b01000001; // RA0をADコンバータピンにし、ADコンバータ機能をEbableに
ADCON1 = 0b10000000; // 結果数値は右寄せ、基準電圧はVDD
ANSEL = 0b00000001; // RA0(AN0)はアナログで読み取りピン
TRISA = 0b00000001; // RA0(AN0)はアナログで読み取りピン(入力)
TRISB = 0x00; // すべて出力
PORTA = 0x00;
PORTB = 0x00;
while (1)
{
tmp = adconv();
for(i = 0; i<tmp; i++){RB3=1;}
__delay_ms(2);
for(i = 0; i<tmp; i++){RB3=0;};
__delay_ms(2);
}
}
unsigned int adconv()
{
__delay_us(20); //アクィジョン時間 20us
ADCON0bits.GO_DONE= 1; //AD変換開始
while(ADCON0bits.GO_DONE); //変換完了待ち
return (ADRESH<<8)+ ADRESL;
}
Re: Duty比を変えるプログラム
10ビットのADRESが「ADRES」で通じるかどうかはコンパイラの仕様です。
ハードとは関係ありません。
※実際にはハードには何の名前もありません。ADRESLやPORTAも単にそのアドレスにあるレジスタの説明上付けた名前です。
その名前で、そのアドレスの内容を制御できるようにコンパイラが関連付けています。
なので、データシートに載っているレジスタ名がそのコンパイラで通じるかさえも実際は判りません。
そのコンパイラが通じる仕様で、提供してくれれば使えばいいですし、
そうでなければ自分で処理する事になります。
勿論、コンパイラの仕様ですから、コンパイラバージョンでも変わるかもしれません。
> ADRES<9:2>
これは、ADRESの第9ビット〜第2ビットまで、と言う事です。
逆に言えば、ADRESの第0、第1ビットは別の所にある、と言う事です。
普通、8ビットしか使わない場合は左詰め(でHIGHしか読まない)、10ビット使う場合は右詰めにします。
> for(i = 0; i<tmp; i++){RB3=1;}
> __delay_ms(2);
> for(i = 0; i<tmp; i++){RB3=0;};
> __delay_ms(2);
> }
これ自体は間違いでは無いです。勿論、元もプログラムでも間違いではありません。
ただ、思っている動作を記述しているのかどうか?です。
普通、この時にやりたいことは
RB3を2*tmp[ms]間HIGH、→RB3を2*tmp[ms]間LOWにする
という考えで作りますよね?
※なぜそうするかというと、__delay_ms(tmp*2);と__delay_ms関数では変数を引数に出来ない仕様だからです。
でも今回のだと、
最初のfor文ではtmp回RB3=1が実行されます。(それでfor文終わり)
次に__delay_ms(2);が1回行われます。
次のfor文でtmp回RB3=1が実行されます。(それでfor文終わり)
(取り忘れでしょうけど「;」が1回行われる?)
で、次に__delay_ms(2);が1回行われます。
つまり、時間の増減に__delay_ms(2);は関わっていません。
{}内にRB3=が入っているので、コンパイラに省略される事は無いでしょう。
> 教科書では
> return(○○)となっているからです。
> 本当に上記の記載方法で上位8ビットと下位2ビットがきちんと並んでいるのだろうかと??
return文には()は要りません。つまり、関数で使うmain「()」の意味とは違います。こちらは引数を入れる場所、という役割があります。
return文に付いているのは、単純に計算時に使う()の意味です。必要以上に付けてもエラーではありません。
return (1+2+3)/4;
と書いても、6/4=「1」が返ります。
「unsigned int」 adconv()
と戻り値が負号なし16ビット整数なので、
return (ADRESH<<8)+ ADRESL;
で、ちゃんと16ビットの整数が返ります。
※勿論、変換結果を右詰めした場合です。
後は、その受け入れ先もそれが入るだけの大きさが必要です。
もし入らない大きさなら、あふれ出た桁は消えます。
ハードとは関係ありません。
※実際にはハードには何の名前もありません。ADRESLやPORTAも単にそのアドレスにあるレジスタの説明上付けた名前です。
その名前で、そのアドレスの内容を制御できるようにコンパイラが関連付けています。
なので、データシートに載っているレジスタ名がそのコンパイラで通じるかさえも実際は判りません。
そのコンパイラが通じる仕様で、提供してくれれば使えばいいですし、
そうでなければ自分で処理する事になります。
勿論、コンパイラの仕様ですから、コンパイラバージョンでも変わるかもしれません。
> ADRES<9:2>
これは、ADRESの第9ビット〜第2ビットまで、と言う事です。
逆に言えば、ADRESの第0、第1ビットは別の所にある、と言う事です。
普通、8ビットしか使わない場合は左詰め(でHIGHしか読まない)、10ビット使う場合は右詰めにします。
> for(i = 0; i<tmp; i++){RB3=1;}
> __delay_ms(2);
> for(i = 0; i<tmp; i++){RB3=0;};
> __delay_ms(2);
> }
これ自体は間違いでは無いです。勿論、元もプログラムでも間違いではありません。
ただ、思っている動作を記述しているのかどうか?です。
普通、この時にやりたいことは
RB3を2*tmp[ms]間HIGH、→RB3を2*tmp[ms]間LOWにする
という考えで作りますよね?
※なぜそうするかというと、__delay_ms(tmp*2);と__delay_ms関数では変数を引数に出来ない仕様だからです。
でも今回のだと、
最初のfor文ではtmp回RB3=1が実行されます。(それでfor文終わり)
次に__delay_ms(2);が1回行われます。
次のfor文でtmp回RB3=1が実行されます。(それでfor文終わり)
(取り忘れでしょうけど「;」が1回行われる?)
で、次に__delay_ms(2);が1回行われます。
つまり、時間の増減に__delay_ms(2);は関わっていません。
{}内にRB3=が入っているので、コンパイラに省略される事は無いでしょう。
> 教科書では
> return(○○)となっているからです。
> 本当に上記の記載方法で上位8ビットと下位2ビットがきちんと並んでいるのだろうかと??
return文には()は要りません。つまり、関数で使うmain「()」の意味とは違います。こちらは引数を入れる場所、という役割があります。
return文に付いているのは、単純に計算時に使う()の意味です。必要以上に付けてもエラーではありません。
return (1+2+3)/4;
と書いても、6/4=「1」が返ります。
「unsigned int」 adconv()
と戻り値が負号なし16ビット整数なので、
return (ADRESH<<8)+ ADRESL;
で、ちゃんと16ビットの整数が返ります。
※勿論、変換結果を右詰めした場合です。
後は、その受け入れ先もそれが入るだけの大きさが必要です。
もし入らない大きさなら、あふれ出た桁は消えます。
猛牛ロック 2018/11/17(Sat) 22:54 No.1217