049911
48時間以内の記事は New Mark で表示されます
無題
初めてのプログラム

皆さんこんばんは。

初めてプログラムを作ってみました。
タイマー0割り込みをつかって、
RB3を常時点燈、RA6に信号が入ったら、RB3を消灯

しかし、RB3がSW ONでいきなりつきません。
どこが悪いのかご指摘願います。
宜しくお願いします。

RA6はプルアップ、RB3はプルダウンです。




/*タッチプローブ*/
// PIC16F1827 Configuration Bit Settings
//RA6 マッハからの信号
// 'C' source line config statements
#include <xc.h>
// CONFIG1
#pragma config FOSC = INTOSC // Oscillator Selection (INTOSC oscillator: I/O function on CLKIN pin)
#pragma config WDTE = OFF // Watchdog Timer Enable (WDT disabled)
#pragma config PWRTE = OFF // Power-up Timer Enable (PWRT disabled)
#pragma config MCLRE = OFF // MCLR Pin Function Select (MCLR/VPP pin function is digital input)
#pragma config CP = OFF // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config CPD = OFF // Data Memory Code Protection (Data memory code protection is disabled)
#pragma config BOREN = ON // Brown-out Reset Enable (Brown-out Reset enabled)
#pragma config CLKOUTEN = OFF // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)
#pragma config IESO = OFF // Internal/External Switchover (Internal/External Switchover mode is disabled)
#pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is enabled)
// CONFIG2
#pragma config WRT = OFF // Flash Memory Self-Write Protection (Write protection off)
#pragma config PLLEN = OFF // PLL Enable (4x PLL disabled)
#pragma config STVREN = ON // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will not cause a Reset)
#pragma config BORV = HI // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
#pragma config LVP = OFF // Low-Voltage Programming Enable (High-voltage on MCLR/VPP must be used for programming)
// __delay_ms(), __delay_us()関数が使用する
#define _XTAL_FREQ 8000000
#define On 1
#define Off 0

//プロトタイプ宣言
void InitInterTimer0 (void);
void interrupt isr ( void )
{//TMR0の割り込み処理
if(RA6==Off )
{

RB3=Off;
INTCONbits.TMR0IF=0;//タイマ0割り込みが入った際、TMR0IFが1になるので、0で初期化
INTCONbits.TMR0IE=1;//タイマー0を有効化
}
}
// メイン関数
void main (void){
OSCCON = 0b01101001;//内蔵発振器 8MHz使用に設定
PORTA = 0x00;// 電圧レベルの初期設定
PORTB = 0x00;
// 入出力設定
TRISA = 0b00110000;//RA5は入力専用・RA6は入力,他は出力
TRISB = 0b00000000;//RB3はLED用出力
//初期設定
RB3=On;
RA6=On;

InitInterTimer0 ();
INTCONbits.GIE=1;

while(1){

RB3=On;
}
}
//タイマ0割込み設定関数
void InitInterTimer0 (void)
{//割り込み設定
OPTION_REG=0b100000000;//プリスケラ000  5ビット=0内部クロック使用 WDTは使わない
TMR0=0x00;
INTCONbits.TMR0IF=0; //TMR0フラグクリアー
INTCONbits.TMR0IE=1;//TMR0割り込み許可
INTCONbits.GIE=1;//全体割り込み許可
}

TR 2018/11/29(Thu) 21:41 No.1261  記事編集
Re: 無題
プログラムの方はまだちゃんと見ていませんけど、回路図をみると、RB3は
・LOW出力で点灯
・HIGH出力で消灯
・入力時(プルアップ無)で弱点灯
という回路になっています。

※LEDを光らせるのにプルする必要はありません。
猛牛ロック   2018/11/29(Thu) 22:30 No.1262 記事編集
Re: 無題
TRさん,猛牛ロックさん,こんばんは。

TRさん,頑張ってますね。
私の環境でも通りますので,シンタックスエラーはないようです。

これが一番やっかいなんです。

ここからは,自分のやりたいことが表現?されているか,
一つ一つつぶす作業だと思います。

回路については,ちょと私は,分からないところがあるのですが,正しいものとしてプログラムだけ見ました。

忘れてしまっている部分も多いので,なんともいえないのですが,

TRさんのプログラムだと,

  RA6=On

の時の処理が割り込み処理に書かれてないように思います。次のようにしてはどうでしょうか。

void interrupt isr ( void ){//TMR0の割り込み処理
if(RA6==Off ){
RB3=Off;
}
if(RA6==On ){
RB3=On;
}
INTCONbits.TMR0IF=0;//タイマ0割り込みが入った際、    TMR0IFが1になるので、0で初期化
INTCONbits.TMR0IE=1;//タイマー0を有効化
}

こうした上で,main の

while(1){
RB3=On;
}


while(1){
} 

のようにしてみてはどうでしょうか。実際にやってみないので,動くかはは分かりません。

それと,このままだとLEDがちらつくかも。

スイッチが押された時に,一度だけLEDをONにする,

それと,LEDをOffにするのは,LEDがOnの時だけにする,

等の判断をいれないと,同じ処理を何度も繰り返すことに

なると思います。
mabo   2018/11/29(Thu) 22:31 No.1263 記事編集
Re: 無題
猛牛ロックさんへ

>・LOW出力で点灯  → これは分かります。
・HIGH出力で消灯   → これも分かります。
・入力時(プルアップ無)で弱点灯  これがわかりませんので、教えてください。
という回路になっています。

※LEDを光らせるのにプルする必要はありません。   ここも教えてください。


追記
PICのI/Oってよくわからないのですが、
ひょっとして、RB3のプルダウン抵抗は、RB3に何もつながっていない場合は、10kオームの抵抗は必要だけど、
LEDをつける場合は、逆に、電圧が、180kオームとLEDと10キロΩによって分圧されるということですか?
TR   2018/11/29(Thu) 22:49 No.1264 記事編集
Re: 無題
maboさんへ


>同じ処理を何度も繰り返すことに


なるほど〜。
タイマー0割り込みって奥が深い。

フラグを使えばいいのかも!
TR   2018/11/29(Thu) 23:11 No.1265 記事編集
Re: 無題
プログラムを一通り見ました。

> #define On 1
> #define Off 0

回路的にはSWもLEDもアクティブローです。

あと、通常のPICは
PORTレジスタは読み取り用、
LATレジスタは出力用
となります。使い分けた方が良いです。


> while(1){
>
> RB3=On;
> }
これだと、仮にタイマー割り込みで消灯したとしても気が付きません。
すぐに点灯します。

タイマー割り込みをするなら、割り込みがかかる周期を把握した方が良いです。
普通は、キッチリとした時間が欲しいからタイマー割り込みを使うのです。

> PORTA = 0x00;// 電圧レベルの初期設定
> PORTB = 0x00;

> //初期設定
> RB3=On;
> RA6=On;

2回初期設定しても意味がありません。
また、RA6=Onと入力ピンに代入しても意味がありません。

> 入力時(プルアップ無)で弱点灯
入力時(プルアップ無)はハイインピーダンスです。
つまり、PICとは繋がっていないのと同じ状態です。
5V---150Ω---LED---10kΩ---GND
という回路ですから、0.3mA程度流れる筈です。
部屋を暗くすれば十分に光っているのが判る筈ですけど。


> ※LEDを光らせるのにプルする必要はありません。
入力時にプルをするのは、未接続時には、いろんな電圧値を示す為です。
例えば、SW-5Vと繋ぐなら、SWオンのときはHIGHレベルになります。でも
未接続だと、SWオフの時はHIGHの時もあればLOWになる時もあります。
なので、押していない時の識別の為に、押した時と逆側にプルします。

出力時は、HIGH/LOWいずれにしても、どちらかをを出力します。
LEDの場合は直接的に駆動させるだけです。プル抵抗は無駄な電気を使うだけです。
ただし、トランジスタを使う場合はPICが駆動されない(電源が入っていない)時や入力の場合に
つまり、上記で言う未接続相当の時に、トランジスタのゲート或いはベースがトランジスタをオンにしてしまう電圧に
なる場合があります。そういった誤動作を防ぐためにプルします。

追記します。

MABOさんのが正しい処理です。LEDがちらつくこともありません。

ただし、main関数で
while(1){
}
として、タイマー割り込みで
if(RA6==Off ){
RB3=Off;
}
if(RA6==On ){
RB3=On;
}
とするなら、最初からmain関数で
while(1){
if(RA6==On ) RB3=On;
else RB3=Off;
}
とすれば良いです。タイマー割り込みを使う意義がありません。


更に追記します。

押す度にオンとオフを繰り返すようなプログラムなら、フラグ処理が必要です。
また、チャタリング現象の考慮も必要になります。

あと、
if(RA6==Off ){
RB3=Off;
}
if(RA6==On ){
RB3=On;
}
は、短くすると
RB3=RA6;
でも良いはずです。
猛牛ロック   2018/11/29(Thu) 23:38 No.1266 記事編集
Re: 無題
猛牛ロックさん,TRさん,こんにちは。

猛牛ロックさん,適切なアドバイス,ありがとうございます。

いつものことながら見識の深さにおどろかされます。



TRさん,書き込みいただいたプログラム,うまく動いたでしょうか。

私も,割り込み処理等の動作確認で,TRさんの書かれたようなLEDチカのプログラムよくつかいました。

X IDEには,シュミレーターもついていて,それを動かせば,各値等の確認できるようですが,実際にLED等で,確かめた方が私にはてっとりばやいです。

タイマーフラグのクリアーやらレジスターの再設定等,TRさんが書かれたプログラムのように書いて,

思った動作をしないで,悩んだことも多々あります。

この辺は,きっと,場数なんでしょうかね。
mabo   2018/11/30(Fri) 12:19 No.1267 記事編集
Re: 無題
みなさんこんばんは。

猛牛ロックさんいつもありがとうございます。
maboさんも、いろいろとご指導に感謝します。


タイマー0割込みですが、キットで遊ぼうの域からは脱していません。
今のところ、以下のプログラムです。


最初は、入力SWから、出力端子の操作ができるかと思ったのですが、ダメでした。
外部割込みなら行けそうですが、
外部割込みをやってみます。


それと、入力端子を使っての出力端子の操作は、1827で出来るのでしょうか、
というのも、ツールラボさんの記事を見ていたら、IOCAN3 = 1;
IOCANレジスタなんですね、これは、PORTA3番ピンに機能があって、この機能を使えば
簡単に入力端子のHiでプログラムを組めるようです。
ツールラボさんは、1823でしたっけ、、、。


それとハイインピーダンスの件、ありがとうございます。
I/Oピンの仕組みはまだよくわかっていないです。
でも想像した通り、180オーム-LED-10kオームで分圧されてしまうようですね。


常時RB3を点灯させ、
タイマー0割込みで、RB4を点滅させています。

// PIC16F1827 Configuration Bit Settings

// 'C' source line config statements
#include <xc.h>
// CONFIG1
省略
#pragma config LVP = OFF // Low-Voltage Programming Enable (High-voltage on MCLR/VPP must be used for programming)
// __delay_ms(), __delay_us()関数が使用する
#define _XTAL_FREQ 1000000
#define On 1
#define Off 0
// プロトタイプ宣言
void InitInterTimer0 (void);

// メイン関数
void main (void)
{
OSCCON = 0b01011010; // 内部クロック周波数を1MHzに設定
// 電圧レベルの初期設定
PORTA = 0xFF;
PORTB = 0xFF;
// 入出力設定
TRISA = 0x20;
TRISB = 0x00;

// タイマ0割込み設定関数の呼び出し
InitInterTimer0();
// 割込み全体の許可
GIE = 1;
// 永久ループ
while(1)
{
RB3 =1;
}
}

// 割込みサービスルーチン
static void interrupt isr()
{
RB4 =1;
__delay_ms(3000);
RB4=0;
__delay_ms(3000);
// タイマ0割込みフラグをクリア
T0IF = 0;
}

// タイマ0割込み設定関数
void InitInterTimer0 (void)
{
OPTION_REG=0b000000000;//プリスケラ000  5ビット=0内部クロック使用 WDTは使わない
TMR0=0x00;
INTCONbits.TMR0IF=0; //TMR0フラグクリアー
INTCONbits.TMR0IE=1;//TMR0割り込み許可
INTCONbits.GIE=1;//全体割り込み許可
}
TR   2018/11/30(Fri) 22:45 No.1268 記事編集
Re: 無題
> でも想像した通り、180オーム-LEDる-10kオームで分圧されてしまうようですね。

いいえ、単なる直列回路です。入力時は、
5V-10180オーム-LED-GND
と同じと言う事です。
HIGH出力時は、LEDは5Vと5V(HIGH)に挟まれているので、LEDには電気が流れませんけど、10kΩには電気が流れます。
つまり、無駄です。
LOW出力時には5V-LED-LOWと流れるのでLEDは光ります。10kΩの方には電気は流れません。
いずれにしても、10kΩは付ける意味がありません。

> 入力SWから、出力端子の操作ができるかと思ったのですが
言っている意味が解りません。
プログラムのどこからでも出力端子は操作できます。
RB3をLOWにしたいと言う事でしょうか?
それなら
RB3=0;
と書けばLOWになります。


> IOCANレジスタなんですね、
F1827の基本的な構成として、入力がポートB、出力がポートAに割り当てられています。
まぁ、絶対的なものではありませんけど。
で、同じもの(INT/IOC)は1827にもありますけど、ポートBです。


で、今回のプログラムですけど、悪い例です。
タイマー割り込みは正確な時間を作り出します。
しかし、このプログラムでは__delay_ms(3000);で、正確な時間の取得を壊しています。
なぜなら、タイマー割り込みの間隔を超えているからです。
また、タイマー割り込みを使う意味も全くありません。
タイマー割り込みを使うもう一つの利点はdelay関数を使わないプログラムにする、という点です。

まずは、タイマー割り込みの時間(間隔)を把握しましょう。
1msや10msにしても良いですし、中途半端な値でも駄目ではありません。
駆動周波数とプリスケーラ、タイマー値から、算出(設定)してください。
それがタイマー0の単位時間です。単位時間内に収まる処理にする必要があります。


※基本的には、周辺機能(タイマーや外部割り込み等)は使わずにGPIO操作を覚えた方が良いです。
まずはGPIO操作で、壁にぶつかるまで押し通した方が良いです。
今は分散してしまっていて、見通し悪いプログラムになっていて、自分で原因を見つけるのが困難になっています。
CONFIGやクロック設定などは、どっかからのコピーで良いですけど、ピン操作(初期設定)からは、
どう制御しているのか、100%自信をもって書いてください。
理解せずに動いても意味がありません。
逆に、理解していないものを書いてはいけません。
自分の理解と共に、出来る範囲を増やす事です。
特に動かないのを、何故そうなったか理解しようとせずに、他の機能に移るのは止めるべきです。
動かないのは、目の前に覚えるべきことがあるからです。
そこを乗り越えてはじめて、1つスキルが上がるのです。
猛牛ロック   2018/12/01(Sat) 00:30 No.1269 記事編集
Re: 無題
猛牛ロックさん,TRさん,こんばんは。

猛牛ロックさん,今日もありがとうございます。

TRさん,新しいプログラムですね。

割り込みの中で,

__delay_ms(3000);

をお使いのようですが,好みからいったら,割り込みに入った回数をカウントして,LEDのOnとOffを交互にすればいいように思いますが,どうでしょうか。

static void interrupt isr(){
 if(Count<一定数){Count++;}
 Else{ Count=0;RB4=RB4~;}

T0IF = 0;


間違ってるかもしれませんが,上記のようにすれば,いいかもですね。

それから,

 RB3

ですけど,1回だけOnにすれば,いいので,

RB3 =1;
while(1)
{
}

みたいにWhileの外にだした方いいと思います。
Whileの中にあると,RB3を1にする動作を繰り返すことになります。


今日は,ちょっと,下記を参考にシュミレートをいろいろやってみました

http://www.geocities.jp/zattouka/GarageHouse/micon/MPLABX/Simulator1.htm
mabo   2018/12/01(Sat) 01:09 No.1270 記事編集
Re: 無題

>F1827の基本的な構成として、入力がポートB、出力がポートAに割り当てられています。
 ・・・・・・
で、同じもの(INT/IOC)は1827にもありますけど、ポートBです。


そうか!
データシートを見るとありました。
写真の赤枠!
1827の場合、ピンに入った信号を読み取る場合、読み取れる選択肢は、
bit0〜bit7までの全てですね! オー、沢山ある。

RB6に割り込み有効化
IOCIE = 1;
IOCBN3 = 1;
GIE = 1;

常時動作

RB6 割り込み無効化
GIE = 0;
IOCIE = 0;
IOCBN3 = 0;

割り込み処理プログラム
void interrupt isr(void)
{

}


これで、常時動作の最中にRB3にLo信号が入れば、割込みができると思いますが。



>単位時間内に収まる処理にする必要があります。


サブルーチンの作業時間は、タイマー割り込みの時間(間隔)内にするということですか?
今は、
サブルーチンは、割込みが始まって、RB4 =点灯〜3秒据え置き〜RB4消灯〜3秒据え置き
 そして、メイン関数内のRB3点灯させています。

サブルーチン内の割込み開始から割込み作業終了の間の時間(点灯3秒+消灯3秒)をタイマー割込み時間(間隔)内にするのですか?
タイマー割込み時間(間隔)内にする作業の種類にするということですか?

タイマー割込み時間(間隔)内にRA6がハイかローかの確認作業など


>※基本的には、周辺機能(タイマーや外部割り込み等)は使わずにGPIO操作を覚えた方が良いです。
まずはGPIO操作で、壁にぶつかるまで押し通した方が良いです。


自分は、進みます。
これからも宜しくご指導願います

TR   2018/12/01(Sat) 08:28 No.1271 記事編集
Re: 無題
maboさん,こんにちは。


>割り込みの中で,

__delay_ms(3000);

をお使いのようですが,好みからいったら,割り込みに入った回数をカウントして,LEDのOnとOffを交互にすればいいように思いますが,どうでしょうか。

static void interrupt isr(){
 if(Count<一定数){Count++;}
 Else{ Count=0;RB4=RB4~;}

T0IF = 0;


プログラム全体を見させていただけませんか?




>それから,

 RB3

ですけど,1回だけOnにすれば,いいので,

RB3 =1;
while(1)
{
}

みたいにWhileの外にだした方いいと思います。
Whileの中にあると,RB3を1にする動作を繰り返すことになります。



分かりました。



>今日は,ちょっと,下記を参考にシュミレートをいろいろやってみました

http://www.geocities.jp/zattouka/GarageHouse/micon/MPLABX/Simulator1.htm


シュミレーターの使い方なんですね。
機会があったら、見ようかと思います。ありがとうございました。
TR   2018/12/01(Sat) 08:39 No.1272 記事編集
Re: 無題
TRさん,猛牛ロックさんおはようございます。

TRさん,プログラムの全体ですが,

1268のTRさんのプログラムで,割り込みの部分だけを
入れ替えて,main の方で,RB3を外にだせばいいと思います。

割り込みのなかで,

 T0IF = 0;

を使ってますが,もしかして,コンパイル通らないかもですね。

 T0IF = 0→INTCONbits.TMR0IF=0

でしょうか。

カウントの定数は,オーバーフローしない範囲で,
好みでいいと思います。

定数を多くすれば,点滅の間隔が長くなります。

この間隔は,割り込みの時間等を考えれば,割り出せるのでしょうが,私は,適当なことが多かったです。

ただ,タイマーのプログラムで使った時は,だいたい正確な時間になるように,トライアンドエラーで調整しました。
mabo   2018/12/01(Sat) 09:29 No.1273 記事編集
Re: 無題
皆さん方のご指摘を踏まえて、下記の通りプログラムを変えました。

常時は、フラグによりRB3をハイにしたりローにしたりの動作です。

割込み時には、エベントフラグが0なら、強制的に
イベントフラグを1にさせます。

しかし、XIDEのバージョンの関係かどうかわかりませんが
@にエラーが出ています。
以前のNo1268ではそんなことがなかったのに( 一一)
プログラムが悪いのでしょうか?


// PIC16F1827 Configuration Bit Settings
//RA6 マッハからの信号
// 'C' source line config statements
#include <xc.h>
// CONFIG1
#pragma config FOSC = INTOSC // Oscillator Selection (INTOSC oscillator: I/O function on CLKIN pin)
#pragma config WDTE = OFF // Watchdog Timer Enable (WDT disabled)
#pragma config PWRTE = OFF // Power-up Timer Enable (PWRT disabled)
#pragma config MCLRE = OFF // MCLR Pin Function Select (MCLR/VPP pin function is digital input)
#pragma config CP = OFF // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config CPD = OFF // Data Memory Code Protection (Data memory code protection is disabled)
#pragma config BOREN = ON // Brown-out Reset Enable (Brown-out Reset enabled)
#pragma config CLKOUTEN = OFF // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)
#pragma config IESO = OFF // Internal/External Switchover (Internal/External Switchover mode is disabled)
#pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is enabled)
// CONFIG2
#pragma config WRT = OFF // Flash Memory Self-Write Protection (Write protection off)
#pragma config PLLEN = OFF // PLL Enable (4x PLL disabled)
#pragma config STVREN = ON // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will not cause a Reset)
#pragma config BORV = HI // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
#pragma config LVP = OFF // Low-Voltage Programming Enable (High-voltage on MCLR/VPP must be used for programming)
// __delay_ms(), __delay_us()関数が使用する
#define _XTAL_FREQ 1000000
#define On 1
#define Off 0
int event;
// プロトタイプ宣言
void InitInterTimer0 (void);
// メイン関数
void main (void)
{
OSCCON = 0b01011010; // 内部クロック周波数を1MHzに設定
// 電圧レベルの初期設定
PORTA = 0x00;
PORTB = 0x00;
// 入出力設定
TRISA = 0x00;
TRISB = 0x00;
// タイマ0割込み設定関数の呼び出し
InitInterTimer0();
// 割込み全体の許可
GIE = 1;
event=0;//初期値イベント無しRB3ロー
// 永久ループ
while(1)
{
if(event==1)
{
RB3=0;
}
if(event=1){
RB3=1;
}

// 割込みサービスルーチン
@static void interrupt isr()
{
if(RA6==0 && event==0){//もしRA6が押されていて、イベントが起きていなかったら
event=1;
}
// タイマ0割込みフラグをクリア
T0IF = 0;
}

// タイマ0割込み設定関数
void InitInterTimer0 (void)
{
OPTION_REG=0b000000000;//プリスケラ000  5ビット=0内部クロック使用 WDTは使わない
TMR0=0x00;
INTCONbits.TMR0IF=0; //TMR0フラグクリアー
INTCONbits.TMR0IE=1;//TMR0割り込み許可
INTCONbits.GIE=1;//全体割り込み許可
}
TR   2018/12/01(Sat) 10:20 No.1274 記事編集
Re: 無題
maboさんへ

>1268のTRさんのプログラムで,割り込みの部分だけを
入れ替えて,main の方で,RB3を外にだせばいいと思います。


それでも、良いと思います。



>割り込みのなかで,

 T0IF = 0;

を使ってますが,もしかして,コンパイル通らないかもですね。

 T0IF = 0→INTCONbits.TMR0IF=0

でしょうか。

それは、XIDEのバージョンの関係でコンパイルできなくなります。
今自分は、コンパイルできなくなるのでV3.65を使っています。
V3.65なら、T0IF = 0 でとおります。


猛牛ロックさんが、割込み時間を気にしているのは、
SWによってLEDの操作を考えていると思います。
本来のタイマー0割込みの使い方をしろと言っていると思います。

自分はそう、解釈し新しいプログラムをNo1274に掲載しました。
TR   2018/12/01(Sat) 10:28 No.1275 記事編集
Re: 無題
TRさん,猛牛ロックさん,こんにちは

TRさん,新しいプログラムですね。

今回は,スイッチ(RA6経由)でLED(RB3)をつける
というプログラムで,スイッチの判断を割り込みで検出するということでしょうか。

これを発展させば,チャタリングの除去等もできますね。

一カ所だけあきらかな間違いがあります。

while(1)
{
if(event==1)
{
RB3=0;
}
if(event=1){
RB3=1;
}

の if(event=1) の部分で,

 if(event==0)

でしょうかね。

@のエラーはちょっと不明です。
mabo   2018/12/01(Sat) 12:44 No.1276 記事編集
Re: 無題
maboさんこんにちは。

ご指摘ありがとうございます。
早速直しました(笑い

エラー表示をグーグル翻訳すると ↓
main.c:62:警告:(2025)ローカル変数 "isr"の修飾子 "interrupt"は許可されておらず無視されています

しかし、No1268ではそんなことがなかったのに(参った
TR   2018/12/01(Sat) 14:40 No.1277 記事編集
Re: 無題
TRさん,もしかして空白の問題かも。

isr()→isr ()

X IDEのディターでは,()と関数名の間に空白があるようです。
mabo   2018/12/01(Sat) 14:56 No.1278 記事編集
Re: 無題
maboさんへ

>X IDEのディターでは,()と関数名の間に空白があるようです。

空白を入れても駄目です。
TR   2018/12/01(Sat) 16:56 No.1279 記事編集
Re: 無題
ちょっと成形すれば、buildは出来ますよ。
「}」は付けましたか?

SOURCE→FORMATで成形してみた方が良いです。すぐに判ります。

ただし、実行しても何も変化はしない気がします。


<追記します。>

プログラム的には

> PORTA = 0x00;
> PORTB = 0x00;
> // 入出力設定
> TRISA = 0x00;
> TRISB = 0x00;

で、RA3はLOW出力です。※RA6もまたLOW出力です。

タイマー割り込みがかかると
> if (RA6 == 0 && event == 0) {//もしRA6が押されていて、イベントが起きていなかったら
> event = 1;
> }
で、eventが1になります。
※初期化はint event;ではなく、volatile int event;にした方が良いです。

そして、メイン関数の永久ループで、
if (event == 1) {
RB3 = 0;
}
と、元々LOW出力のピンをLOW出力にします。

ちょっと、どうしたいのか、プログラム以前に、目的とする動作が判りません。
どういったプログラムが書きたかったのでしょうか?

元々HIGH出力のRB3を、一度スイッチが押されたらLOW出力に固定したい、という事ですか?
それとも、毎回押す度にトグル動作、とかでしょうか?
猛牛ロック   2018/12/01(Sat) 17:01 No.1280 記事編集
Re: 無題
猛牛ロックさんこんばんは。


>「}」は付けましたか?


つけ忘れていました。
つけたら、エラー表示がなくなりビルトもできました。

これなら、動作しますかね?

動作
SW On(プルアップRA6がLo)→ RB3がハイ
RB3は、プルアップもプルダウンもなしで、RB3からLED〜180Ω〜GND

SWは、押している時間だけSWが入るタイプです。



でなんですが、、、、

実は、PICの差し込みを間違えて自作の書き込み機が壊れたようです。




>SOURCE→FORMATで成形してみた方が良いです。すぐに判ります。

この方法を教えてください。

色々とすみません。宜しくお願いします。
TR   2018/12/01(Sat) 20:30 No.1282 記事編集
interrupt関数
みなさんこんばんは。

F1827で、以下のプログラム(もとは、猛牛ロックさん作成)ですが、大変重宝しています。
F1827でコンパイルするとエラーが出ます。
IDXは、interrupt関数に!が出ています。
原因を分かったらご教授願います。


/*間欠*/

// PIC16F1827 Configuration Bit Settings

// 'C' source line config statements

// CONFIG1
#pragma config FOSC = INTOSC // Oscillator Selection (INTOSC oscillator: I/O function on CLKIN pin)
#pragma config WDTE = OFF // Watchdog Timer Enable (WDT disabled)
#pragma config PWRTE = OFF // Power-up Timer Enable (PWRT disabled)
#pragma config MCLRE = OFF // MCLR Pin Function Select (MCLR/VPP pin function is digital input)
#pragma config CP = OFF // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config CPD = OFF // Data Memory Code Protection (Data memory code protection is disabled)
#pragma config BOREN = ON // Brown-out Reset Enable (Brown-out Reset enabled)
#pragma config CLKOUTEN = OFF // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)
#pragma config IESO = OFF // Internal/External Switchover (Internal/External Switchover mode is disabled)
#pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is enabled)

// CONFIG2
#pragma config WRT = OFF // Flash Memory Self-Write Protection (Write protection off)
#pragma config PLLEN = OFF // PLL Enable (4x PLL disabled)
#pragma config STVREN = ON // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will not cause a Reset)
#pragma config BORV = HI // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
#pragma config LVP = OFF // Low-Voltage Programming Enable (High-voltage on MCLR/VPP must be used for programming)

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

#include <xc.h>

#define KanketuTime 2
#define DousaTime 1
#define On 0
#define Off 1
// __delay_ms(), __delay_us()関数が使用する
#define _XTAL_FREQ 4000000
int Start;

// プロトタイプ宣言
void InitInterTimer0 (void);
void WaitTime (int cnt);

// メイン関数
void main (void){
OSCCON = 0b01101010;//内蔵発振器 4MHz使用に設定
PORTA = 0x00;// 電圧レベルの初期設定
PORTB = 0xFF;
// 入出力設定
TRISA = 0b01010000;//RA5は入力専用・RA6は入力他は出力
TRISB = 0b00000000;//RB0は入力
//初期設定
RA2=Off;//MACH
RA6=Off;
Start=0;
// タイマ0割込み設定関数の呼び出し
InitInterTimer0();
// 割込み全体の許可
GIE = 1;
int Buzer=0;//

// 永久ループ
while(1){
if(Start==1){//スタートフラグが1なら動作開始
RA2=On;
Buzer=On;
Second(DousaTime);
//RA2=Off;
//Second(KanketuTime);
}
if(Start==0){
if(Buzer==On){
Second(KanketuTime);
RA2=Off;
Buzer=Off;
}

}
}
}

static void interrupt isr()
{//TMR0の割り込み処理(割り込みサブルーチン)
if(INTCONbits.TMR0IF==1){//割り込みがあったら
TMR0 =0 ; // タイマー0の初期化
if(RA6==0){//MACHからの信号をしらべて0(Low)だったらスタートのフラグを1にする
if(Start==0){
Start=1;
}
}
if(RA6==1){//MACHからの信号をしらべて1(High)だったらスタートのフラグを0にして
if(Start==1){
Start=0;
//RA2=Off;//機器の動作を強制的に止める。
}
}
INTCONbits.TMR0IF=0;
TMR0=0;
}
}

// タイマ0割込み設定関数
void InitInterTimer0 (void)
{//割り込み設定
OPTION_REG=0b000000000;//プリスケラ? 2 5ビット=0 WDTは使わない
TMR0=0; //TMR0カウンターを0に
INTCONbits.TMR0IF=0; //TMR0フラグクリアー
INTCONbits.TMR0IE=1;//TMR0割り込み許可
INTCONbits.GIE=1;//全体割り込み許可
}

// 待ち時間関数}
void Second(int sec){
while(sec >0){
sec--;
__delay_ms(10);
}
}
TR 2018/11/26(Mon) 20:33 No.1249  記事編集
Re: interrupt関数
> !が出ています。

元のプログラムと見比べてみてください。
何が変わっているのか。
場所は「!」が付いているので判っているんですよね?
更にコンパイルすればエラーメッセージが出ると思います。
猛牛ロック   2018/11/27(Tue) 12:42 No.1250 記事編集
Re: interrupt関数
猛牛ロックさんありがとうございます。
自分なりに、データシートを見たりして、プログラむ見直しをしたりして、
現在は以下の通りですが、
エラーの表示は、
interrupt関数に「!」の表示はそのままです。
でも何度見ても、エラーには思えないプログラム内容です。
エラー原因をわかりましたら、教えてください。
宜しくお願いします。

エラー表示も添えておきます。
なお、グーグル翻訳では、翻訳しきれませんでした。


エラー表示内容

make -f nbproject/Makefile-default.mk SUBPROJECTS= .build-conf
make[1]: Entering directory 'C:/Users/TOSHI/MPLABXProjects/LESSON_C.X'
make -f nbproject/Makefile-default.mk dist/default/production/LESSON_C.X.production.hex
make[2]: Entering directory 'C:/Users/TOSHI/MPLABXProjects/LESSON_C.X'
"C:\Program Files (x86)\Microchip\xc8\v2.00\bin\xc8-cc.exe" -mcpu=16F1827 -c -fno-short-double -fno-short-float -O0 -fasmfile -maddrqual=ignore -xassembler-with-cpp -Wa,-a -DXPRJ_default=default -msummary=-psect,-class,+mem,-hex,-file -ginhx032 -Wl,--data-init -mno-keep-startup -mno-osccal -mno-resetbits -mno-save-resetbits -mno-download -mno-stackcall -std=c99 -gdwarf-3 -mstack=compiled:auto:auto -o build/default/production/main.p1 main.c
main.c:71:6: error: variable has incomplete type 'void'
void interrupt isr(){//TMR0<82><U+030A><84><82><U+835E><82><U+074F><88><97><9D>
^
main.c:71:15: error: expected ';' after top level declarator
void interrupt isr(){//TMR0<82><U+030A><84><82><U+835E><82><U+074F><88><97><9D>
^
;
2 errors generated.
make[2]: *** [build/default/production/main.p1] Error 1
(908) exit status = 1
nbproject/Makefile-default.mk:106: recipe for target 'build/default/production/main.p1' failed
make[2]: Leaving directory 'C:/Users/TOSHI/MPLABXProjects/LESSON_C.X'
nbproject/Makefile-default.mk:90: recipe for target '.build-conf' failed
make[1]: Leaving directory 'C:/Users/TOSHI/MPLABXProjects/LESSON_C.X'
nbproject/Makefile-impl.mk:39: recipe for target '.build-impl' failed
make[1]: *** [.build-conf] Error 2
make: *** [.build-impl] Error 2

BUILD FAILED (exit value 2, total time: 1s)










//*****************************
//* 間欠タイマー
//* 16F627A
//* XC8 V1.35
//* No481
//* RA6←MACHからの入力想定
//* RA2←制御機器へ
//*****************************
#include <xc.h>
#define _XTAL_FREQ 4000000 //delay用宣言
// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.
// CONFIG
#pragma config FOSC = INTOSCIO // Oscillator Selection bits (INTOSC oscillator: I/O function on RA6/OSC2/CLKOUT pin, I/O function on RA7/OSC1/CLKIN)
#pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = ON // Power-up Timer Enable bit (PWRT enabled)
#pragma config MCLRE = OFF // RA5/MCLR/VPP Pin Function Select bit (RA5/MCLR/VPP pin function is digital input, MCLR internally tied to VDD)
#pragma config BOREN = OFF // Brown-out Detect Enable bit (BOD disabled)
#pragma config LVP = OFF // Low-Voltage Programming Enable bit (RB4/PGM pin has digital I/O function, HV on MCLR must be used for programming)
#pragma config CPD = OFF // Data EE Memory Code Protection bit (Data memory code protection off)
#pragma config CP = OFF // Flash Program Memory Code Protection bit (Code protection off)
#define KanketuTime 2
#define DousaTime 1
#define On 0
#define Off 1
// __delay_ms(), __delay_us()関数が使用する
#define _XTAL_FREQ 4000000
int Start;

//関数宣言
void Second(int sec);
// プロトタイプ宣言
void InitInterTimer0 (void);
// メイン関数
void main (void){
OSCCON = 0b01101010;//内蔵発振器 4MHz使用に設定
PORTA = 0x00;// 電圧レベルの初期設定
PORTB = 0xFF;
// 入出力設定
TRISA = 0b01010000;//RA5は入力専用・RA6は入力他は出力
TRISB = 0b00000000;//RB0は入力
//初期設定
RA2=Off;//MACH
RA6=Off;
Start=0;
int Buzer=0;//

void InitInterTimer0 (void);
GIE=1;//全体割り込み許可
// 永久ループ
while(1){
if(Start==1){//スタートフラグが1なら動作開始
RA2=On;
Buzer=On;
Second(DousaTime);
//RA2=Off;
//Second(KanketuTime);
}
if(Start==0){
if(Buzer==On){
Second(KanketuTime);
RA2=Off;
Buzer=Off;
}
}
TMR0=0;
TMR0IF=0;
}
}

void interrupt isr(){//TMR0の割り込み処理
if(TMR0IF==1){//割り込みがあったら
if(RA6==0){//MACHからの信号をしらべて0(Low)だったらスタートのフラグを1にする
if(Start==0){
Start=1;
}
}
if(RA6==1){//MACHからの信号をしらべて1(High)だったらスタートのフラグを0にして
if(Start==1){
Start=0;
//RA2=Off;//機器の動作を強制的に止める。
}
}
TMR0=0;
TMR0IF=0;
}
}

// タイマ0割込み設定関数
void InitInterTimer0 (void)
{
//割り込み設定
OPTION_REG=0b000000000;//プリスケラ? 2 5ビット=0 WDTは使わない

INTCONbits.TMR0IF=0; //TMR0フラグクリアー
INTCONbits.TMR0IE=1;//TMR0割り込み許可
INTCONbits.GIE=1;//全体割り込み許可
}

// 待ち時間関数}
void Second(int sec){
while(sec >0){
sec--;
__delay_ms(10);
}
}
TR   2018/11/27(Tue) 20:18 No.1251 記事編集
Re: interrupt関数
TRさん,猛牛ロックさん,こんばんは。

ちょっとご無沙汰してました。

TRさん,自分で試してないので,?ですが,

多分,プロトタイプの宣言ををしてないからかなと推測します。

static void interrupt isr()

の関数がプロトタイプの宣言をしてなくて,

main関数より後にでてくるからだと思います。

多分コンパイラーは,プログラムの先頭から解釈していきますが,

main関数のなかで,プロトタイプの宣言をしてない関数に出会う,

あるいは,main関数より前に書いてない関数に出会うと,

関数の参照ができなくて,エラーがでます。

プロトタイプの宣言,面倒なので,サブ関数をメインの前に,

記述するといいかもです。

確か,私の流儀では,そうしてました。
mabo   2018/11/28(Wed) 00:15 No.1252 記事編集
Re: interrupt関数
No.1249は私の環境ではその部分にはエラーは出ません。

No.1251はMABOさんの言う通り、関数宣言でしょう。
但し、チラッと見ただけですけど、1827用のプログラムになっていないようですし、
内容的にも劣化しているように思います。
猛牛ロック   2018/11/28(Wed) 04:22 No.1253 記事編集
Re: interrupt関数
みなさんこんにちは。

maboさんへ

>プロトタイプの宣言,面倒なので,サブ関数をメインの前に,

記述するといいかもです。


やってみましたが、同じエラーが出ました。




猛牛ロックさんへ

>No.1249は私の環境ではその部分にはエラーは出ません。



そうでしたか〜。


と思って、
IDXにおいて、PICをF627Aに選択して、ビルトしましたが
同じエラーが出ました。

もう、自分レベルにはどうしようもありません。



AM11:51 追記
猛牛ロックさんの 環境 という話から、やむを得ず、
MPLAB のバージョンを変更したら、コンパイルできました。

IDXが3.36
コンパイラが1.42です。

自分には、こんな方法しか思いつきませんでした(泣く

でも、皆さんのおかげで、猛牛ロックさんが考えたプログラムを
自分風にアレンジして、しかも、1827、、違うか1823?の日本語バージョンで
書き込みに成功できて、うれしいです。
感謝申し上げます。

Config、AD、PWM、割り込み、タイマー0 そのほかにも
制御文、等々 学習を深められましたm(__)m

TR   2018/11/28(Wed) 08:35 No.1254 記事編集
Re: interrupt関数
> IDXが
何度か書いていますけど、これってMPLAB X IDEですよね?せめてXIDEにして欲しいです。

> コンパイラが1.42です。
一度バージョンを2.?に上げましたよね?書式がちょっと変わったのかもしれません。
その辺りはコンパイラのマニュアルを見る必要があります。
基本的に、コンパイラの仕様に従うしかありません。
それは初心者でもベテランでも同様です。

で、学習ですけど、私の思うには人のコードを書き換えても上達しません。
まずはデジタル入出力を使った、簡単なものから始めた方が良いです。
※本文にあたる部分が10行以下のもの。

取り敢えず重要な事は
・C言語の書式を覚える。(宣言、初期化、関数、引数、戻り値、変数の型)
・GPIOを操作出来るようになる。(入出力を正しく操作)
・if文、while文(for文)を覚える。
・変数を使えるようになる(フラグ、カウント)
といった事です。

レジスタを詳しく覚える事は、時間の無駄が大きいです。
レジスタを操作すること自体は重要な事ですけど、逆に言えば、適切に設定するだけの事です。
最低限の事だけにしておいた方が良いです。
猛牛ロック   2018/11/28(Wed) 18:18 No.1255 記事編集
Re: interrupt関数
猛牛ロックさんの言われる通りです。
早く書き込めるようになりたいものです。
TR   2018/11/28(Wed) 21:04 No.1256 記事編集
Re: interrupt関数
TRさん,猛牛ロックさん,こんばんは。

TRさん,私の環境でコンパイルしてみました。

   X IDE 5.03→5.05の最新でした。
   X C8  2.00

の最新の環境です。

TRさんのアップした最初のプログラムです。

若干変更しました。まず,プロトタイプの宣言で,

  // プロトタイプ宣言
  void InitInterTimer0 (void);
  void WaitTime (int);
  void Second(int);

のようにvoid Second(int);を付け加えました。

それから,ブログの方に掲載しますが,若干の変更をしたら,

コンパイル通りました。

新しい,コンパイラーは,文法にシビアなようです。

それと,xc.h の読み取りのバグがあるようです。

http://mabo52.sakura.ne.jp/files/newmain.c
mabo   2018/11/28(Wed) 21:41 No.1257 記事編集
Re: interrupt関数
maboさんこんばんは。

自分のは、バージョンを5.2から3.65にした関係で、表の掲示板の画面は開けなかったです。

金曜にXIDE5.2に戻してやってみます。

それから、
PIC3のボードですが、完成しました。といっても、PICの電源に
つけるセラミックコンデンサがありませんが、、、
でも、差し込みピンや電源を分配しやすくするためのピンも
併せてつけたので、これで十分です。
どうせ、バラックでのテストは、やはりブレットボードに頼るようになるのでしょうから、
自作ボードはこれくらいにします。

TR   2018/11/28(Wed) 22:37 No.1258 記事編集
Re: interrupt関数
TRさん,猛牛ロックさん,こんにちは。

今回のプログラム16F1827だったんですね。

以前,猛牛ロックさんにご紹介いただいて,私も使いました。

ただ,クロックが早くなる分,いままで動いていたプログラムが動かなくなったり,

88〜1827への移植に苦労したりました。

LATレジスタ使ったり,間にNOPのアセンブラーいれたり,見よう見まねでやりました。

http://kuri6005.sakura.ne.jp/pic/index.php?%C8%AF%B8%F7%A5%C0%A5%A4%A5%AA%A1%BC%A5%C9%28LED%29%A4%CE%C5%C0%CC%C7%2816F1827%20XC8%29

http://mitt.la.coocan.jp/pic/pic1320_06.html

http://www.microtechnica.tv/faq/faq.cgi?kate=mikroC&faq=16


あたりにその記事があります。私のブログでも,

http://mabo52.sakura.ne.jp/index.php?e=970#cmt257

に関連の記事書いてます。

なんかもういろいろ忘れています。
mabo   2018/11/29(Thu) 11:32 No.1259 記事編集
PIC3ボード製作
みなさんこんばんは。
猛牛ロックさんもF1827を所有という事ですね!
お〜と言う感じ。
自分もすでにポチット行きました。

さてさて、
心機一転でPICを始めることにしました。
最初に、PIC3が安定して書き込みできる環境づくりということで、
外部給電によるPIC3用ボードを作ることにしました。

先ず悩んでいる点があります。
それは、PIC端子の処置です。
プルダウンかプルアップかです。
自分は、プルダウンで行こうかとおもいます。

そこでなんですが、将来、出力端子にした時の事を想定して、写真の様に抵抗2本と
LEDを繋いでみました。
実験では動作しましたが、写真の様な繋ぎ方は、どうなんでしょうか?
アブノーマルでしょうか?

TR 2018/11/23(Fri) 16:29 No.1243  記事編集
Re: PIC3ボード製作
学習ボートは使わないのですか?
あれには外部給電端子もついているので作る必要は無いと思います。

> 自分は、プルダウンで行こうかとおもいます。
それは自由ですけど、参考とするプログラムにはプルアップが多いと思いますよ。
で、大抵は内部プルアップを使います。
※今のマイコンは個別に内部プルアップ出来ます。なので、あまり外には配線しません。

回路図は意図が解りません。
猛牛ロック   2018/11/24(Sat) 11:55 No.1244 記事編集
Re: PIC3ボード製作
こんにちは。

>学習ボートは使わないのですか?
あれには外部給電端子もついているので作る必要は無いと思います。

キットで遊ぼうのぼーどですか、
あのボードは、書き込みが不安定で使い物になりません。
購入当初も、電圧を4.75Vにしたりして、なんで5Vじゃダメなのと思ったりしていました。
そんな中、最近(MPLABのバージョンを最新にした。)は、書き込みが出来なくなり、壊れたと思い買い換えました。

それで、試しにと思って、書き込み専用ボードで書き込んでみると
安定して書きこめるようになりました。
PIC3の電流をLEDの方へ回すには限りがあるようです。
なので、書き込みとLEDなどへ回す電気とを分離して、書き込み専用のボードを作ることにしました。


プログラムをやっていて思っていたのですが、
例えば、
入力のSWをONで、出力LEDをHiとしますよね。

この場合、プルアップとプルダウンでの、
端子をHiにしたりLoにしたりの設定が分かりずらいと思っていました。
統一したらいいのにと思っていました。
PICの事が少しは分かってきたので、新たな視線で考えることにしました。←大袈裟(笑

写真は、今のプランです。LEDは、将来の事です。今は作りませんので、除いて見て下さい。

MCLAの端子は入力専用であり、且つ書き込み時には、PIC3に繋がっていなければならない。
書き込みが出来て、且つMCLAの機能を端子を持たせなければなりません。

プルアップにしました。
これなら、両方の機能を持たせられます。
そうなると、統一した方が分かり易いので、RA側は、全てプルアップに統一となりました。

プルアップの場合、SWがONで、端子は、Loとなる。

出力側は、プルダウン。
入力側が、SwがONの時、出力側端子はLEDがOn。この方がイメージが合う。
この時の端子の電位は
入力側はLoで出力側もLo(電流は、PICに流れる。)

イメージが合うんですよね。

追記
PICの電源にコンデンサを忘れました。

TR   2018/11/24(Sat) 13:58 No.1245 記事編集
Re: PIC3ボード製作
確かに、プルダウン入力とアクティブハイでの出力は、感覚と一緒になります。
けれども、実際の素子や回路の状況でそれが変わるのは仕方がないことです。

それを避けるためには

#define Led_On 0
#define Led_Off 1
#define Sw_On 1
#define Sw_Off 0

等のように間違わないように、また書き換えも楽になるように工夫します。

> あのボードは、書き込みが不安定で使い物になりません。
それはボードのせいでは無いと思います。
それなりの数の購入者が居て、利用されているボードですから、
「書き込みが不安定」という反響がなければ、特にボードには問題は無いと推測します。
勿論、故障と言う事はあるでしょうけど。

「安定した書き込み」を第一に考えるなら、https://www.aliexpress.com/item//32949836067.html
のようなセッティングの楽な物を使う方が良いような気がします。
※これは配線だけを合わせるものです。それだけで多くの人が書き込んでいる実績があります。

第三者の視点で見ると、TRさんが作ろうとしているボードよりも、上記の2つのボードの方が信頼性が高いと言わざるを得ません。
猛牛ロック   2018/11/24(Sat) 18:26 No.1246 記事編集
Re: PIC3ボード製作
キットで遊ぼうのボードで書き込みをしましたが、
やはり駄目でした。
自分のボードは故障していると思われます。
PIC3が故障しているようではないです。

今のところ、自作暫定ボードで書き損じはないので、
自作をやってみます。
TR   2018/11/24(Sat) 20:33 No.1247 記事編集
Re: PIC3ボード製作
みなさんこんばんは。

お陰様で、書き込み専用ボード完成しました。
あたりまえでしょうけど、一発で書き込みが出来ました。
でも、キットで遊ぼうのボードでは、その当たり前が出来ませんでした

写真は、自作ボードで書き込んだ後の、書きこめたかどうかのテストです。
壊れていたキットで遊ぼうのボードは、最後の御奉公です。


11/26追記

No1246について
ボードが出来たので、内容を拝見しました。
間欠のプログラムを思い出しました ↓
#define On 1
#define Off 0
#define 略
#define 略
#define vacuum RA3 //掃除機出力


// 待ち時間関数

}

// メイン関数
void main (void){

// 永久ループ
while(1){

if(MODE==0||(MODE==3&&MACH_sig==0)){//OFF

vacuum=Off;

関連付けさせるには、#defaineを2つ必要なんですね。
プログラムにたけている人は違いますね。

TR   2018/11/25(Sun) 19:52 No.1248 記事編集
No1238から
No1238からの続きです。
猛牛ロックさん、こんばんは。

>速度の考え方は、PCと同じです。
通常、4MHz駆動なら1MHz駆動の4倍速く動いていますから、1MHz→4MHzとすると
動作時間が1/4になります。


やはりそうでしたか。


>(PICクロックの周期)と(Tosc)は同一です。
Fosc「周波数」=1/Tosc です。
で、
TADを「1.6us〜6.4usの間になるように」倍率を選択する、と言う事です。
1MHz駆動ならToscは1usです。そして設定できる倍率は、1,2,4,8、…なので、
2か4を選択する事になります。


なるほど!
有難うございました。


16F1827ですが、
16F1823のデータシートと似ている感じです。


>数値は見つけられなかったですけど、例えば、0.8us〜6.4usのように速い速度のほうが広がったのだと思います。

日本語版をみると、網掛を除いた部分が、推奨値で、1.0〜4.0μsecond となっていますかね?

ただ、FRCって何だろう?
RCはおそらく、抵抗とコンデンサを使ってクロック信号を外部から受ける事だと思っていたのですが。

TR 2018/11/22(Thu) 19:09 No.1239  記事編集
Re: No1238から
16F1823と16F1827は同じシリーズ(ファミリ)です。なので、作りとしては殆ど共通しています。
なので、かなりの部分が同じ説明だと思います。
でも、データシートをまとめられなかったという事は、それなりの違いも存在するということでしょう。

> 網掛を除いた部分が、推奨値で、1.0〜4.0μsecond となっていますかね?
そうです。そこから推測しました。16F88で言えば2〜4usが推奨となります。
でも、設定できない、とかでは無く、測定値は保証しないよ、と言う事なので、
駆動クロックを変更したときには、エラーも無く、範囲外に出てしまう可能性があります。

FRCは単純に、内部のRC構成の発信回路を使った時のFREQUENCYという意味でしょうね。
猛牛ロック   2018/11/22(Thu) 22:47 No.1240 記事編集
Re: No1238から
猛牛ロックさん、色々とご教授を頂きまして有難うございます。

PICは初心者にとって扱いずらいと言っていましたが、
PICのデータシートが分からないと本当に難しいと思います。

そこで、F1827を買うことにしました。F1823はデータシートの日本語版があるので
本来は、F1823を買いなのかもしれませんが、PIN数が少ないんですよね。
試しにF1827を買ってみて、今まで教わった事をデータシートを見ながら、
もう一度、やってみます。

PICにはTimerが0,1,2の3個あると、教科書に有ります。
でも、PWMモジュールを使う場合、何故、Timer2を使うのか知りませんでしたが、
データシートにありました。
やはり、日本語のデータシートを手にしながら、教えて頂いたプログラムをもう一度、やってみるのも良いと思った次第です。

TR   2018/11/23(Fri) 08:21 No.1241 記事編集
Re: No1238から
PICなら、そのシリーズを選択するのが一番いいような気がします。

というのは、有名であっても、あまりに古い石だと、
・コンパイラが異なる
・古い情報となるので削除される
という流れになって、XCの例を見つけるのが困難になります。

また、最新(と言っても、秋月で発売されてから2,3年以内)の石だと情報自体が少なかったり、
また5桁のものや、アナログ機能が豊富なものはもっと複雑になっているので、取りあえず止めた方が良いです。
※マイコンとして薦めないのではなく、そういった機能を使いたい時に使い始めれば良い、という事です。

で、このシリーズ(ファミリ)は、ベーシックなラインにあるマイコンで、特別な物が無いかわりに
現在の標準的な機能はちゃんと揃っています。
まぁ、F88もF627Aもベーシックなラインですけどなのですけど、実質的には引退を控えているマイコン、というマイコンです。
F1827なら、開発の候補に挙がる現役のマイコンでしょう。価格も現役価格です。
※F1827なら所有しています。F88やF627Aはちょっと買う気にはなりませんでした。


ただ、日本語データシートがあるとはいえ、F627AやF88と比べると、マイコン(レジスタ)としては多少複雑になっています。
猛牛ロック   2018/11/23(Fri) 13:54 No.1242 記事編集
ADRES
上限を超えたので新しく投稿しました。


>RB3を2*tmp[ms]間HIGH、→RB3を2*tmp[ms]間LOWにする

済みません。
もう少し分かり易く教えて下さい。お願いします。


return文 有難うございます。

ADRESは、変数宣言で対処しましいた。


//変数宣言
unsigned int Value;


Value=(ADRESH<<8)+ ADRESL;
__delay_us(20); //アクィジョン時間 20us
ADCON0bits.GO_DONE= 1; //AD変換開始
while(ADCON0bits.GO_DONE); //変換完了待ち
return (Value);
TR 2018/11/18(Sun) 07:08 No.1218  記事編集
Re: ADRES
「行おうとしている事はボリュームに対応した点滅」なのですから、通常は
ボリューム(ADC)値×補正倍率を点灯/消灯時間、にしようとしますよね?
ボリューム値が1000なら2秒、100なら0.2秒、となるようにするなら補正倍率を2にします。

なので、通常は2msのディレイを1000回、或いは100回行って時間を合わせます。
RB3=1;
for(i=0;i<tmp;i++)__delay_ms(2);
だと、__delay_ms(2);がtmp回行われます。

> for(i = 0; i<tmp; i++){RB3=1;}

だと、tmp回、RB3=1;が行われます。(この処理時間をTとします。)
そして次行の
__delay_ms(2);
です。
つまり、RB3が1の時間は「T+2ms」ということになります。
Tはボリューム値に比例しますけど、意味のない2msが付きます。


for(i = 0; i<tmp*50; i++)RB3=1;
for(i = 0; i<tmp*50; i++)RB3=0;
のように、適当な倍率回数行う方がボリュームの設定値と点滅間隔の動きが一致します。
けれども、1ループで何クロックかかるかは、初心者には判断付きにくいと思います。

※実際、元のプログラムでは点滅時間が早すぎませんでしたか?

> Value=(ADRESH<<8)+ ADRESL;
> __delay_us(20); //アクィジョン時間 20us
> ADCON0bits.GO_DONE= 1; //AD変換開始
> while(ADCON0bits.GO_DONE); //変換完了待ち
> return (Value);

これは害が無いかもしれませんけど悪いプログラムです。
先頭で、まだADCを始めてさえいないのに
Value=(ADRESH<<8)+ ADRESL;
とADC結果レジスタの値を取得してからADC変換を開始しています。
実際の所、これは前回行ったADCの値がレジスタに残っているでしょうからそれが出力されます。
ちゃんと今回の値を返したいなら変換完了→値を取得という順板を守ってください。

今回の場合は気付かない程度に遅れるだけですけど、これが計算なら、計算をせずに結果を返すような事です。
猛牛ロック   2018/11/18(Sun) 12:54 No.1219 記事編集
Re: ADRES
> MABOさんへ

> PICに比べると親切過ぎる感じですね。
そうですね。

基本的な思想としては、「なるべく低級な作業(レジスタの直接操作)はしない」というのがあるのだと思います。
analogReadやanalogWriteも、使い勝手のいいモデル(分周や周期)が採用されています。
で、そのモデルを外した使い方をするときは、本来は、レジスタを直接操作する方法をしなければならないわけなのですが、
私が見た処、そういった使い方は稀で、大抵は、外部のライブラリを使う、という方が多いです。
つまり、他人が作った、操作し易くなっているもの=ライブラリを多くの人が使っています。
それが見つからなくて最後の手段として、データシートをみて、レジスタを弄る、という感じでしょうか。
勿論、Arduino使いも色々な人がいるでしょうけど。

※低レベルで、きっちりと積み上げていけば、そのデバイスの能力を最大限に活かした、より良いものが出来るのは間違いありません。
けれども、低級な作業を学んでもデバイスを変えたら役に立ちません。
逆に言えば、中級でいろんなデバイスで共通の仕様になっているものを使った方が
覚えるのも優しいし、色んなデバイスでも使え、また、間違いも少なくなる、とも言えます。

そのデバイスを熟知している人でも、やはり多くの行を書いていけば間違いも起こります。
そういった人でさえ、ADC変換でレジスタ操作をするなら、データシートで確認する事は必須でしょう。
でも、analogRead(pin);を使えば5秒で安心して使うことが出来ます。
逆に言えば、仕事で「高度な事」をする人の方がデータシートを参照しなければならないレジスタ操作からは離れて
短時間で安全に操作できる方を優先させます。

実際の所、私も最初は、データシートを見て自分自身で書いていました。
でも、何度か同じような事をすると、前回の物を使いまわすようになります。
そうなってくると、レジスタの内容はちょっと忘れても、その作った関数だけが重要になります。
何度か使っているので、信頼性は多少高くなった、自分の関数です。
でも、Arduinoなら、ほとんど同じものが最初から提供されています。
そちらの方が、信頼性が高く、他の人にとっても判りやすい、と言う事は明白です。
プログラムの開発会社が、そのような中間的なものを使うのは必然だと思います。
(逆に、レジスタ操作なんて(極力)するな、というのが主流でしょう)

で、私としては、レジスタ操作(データシート)と悪戦苦闘して、無駄な時間を使ってしまうPICからは離れた方が良いと
思う次第です。(勿論、ベーシックな部分をおさえるのは重要です。)
ただ、そのデバイスの専門家になる目的ではないので、そのレジスタを覚えることは次の段階では役に立たなくなります。
なので、そのデバイス固有の事は、他の参考サイトからコピーすれば良いと思っています。
ただし、それ以上に安全で、信頼性の高いのが、中間的な処理をしてあるライブラリを使う事です。

※個人サイトは、間違いだらけです。「製作」サイトは仕方がないと思うのですけど、「説明」サイトならもう少し
ちゃんと(過去に書いたプログラムも)管理してもらいたいと思っています。
まぁ、結局の所、それだけマイコンプログラムや電子回路は「間違いが起こりやすい=見つけ辛い」ということなのでしょうけど。
猛牛ロック   2018/11/18(Sun) 14:20 No.1220 記事編集
Re: ADRES
1案

while (1)
{
tmp = adconv();
RB3=1;
for(i = 0; i<tmp; i++){__delay_ms(2);}
RB3=0;
for(i = 0; i<tmp; i++){__delay_ms(2);}

}

案1は、遅すぎです。
maboさんがご紹介下さったURLの動画を見て下さい。


>先頭で、まだADCを始めてさえいないのに
Value=(ADRESH<<8)+ ADRESL;

No1216でプロトタイプ宣言をしたのに、関数を入れ忘れていました。
今のところ、下記のとおりです。


   記
// 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;
unsigned int Value;
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;
unsigned int adconv();
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()
{
Value=(ADRESH<<8)+ ADRESL;
__delay_us(20); //アクィジョン時間 20us
ADCON0bits.GO_DONE= 1; //AD変換開始
while(ADCON0bits.GO_DONE); //変換完了待ち
return (Value);
}
TR   2018/11/18(Sun) 18:56 No.1221 記事編集
Re: ADRES
まず、行っている事の目的があります。
最初にも言ったように、プログラム的には「間違い」ではありません。

参考サイトは簡単に言えば、「A/D変換の結果を目視で確認する」というものです。
それなのに、プログラムが悪かったので、その動画のように訳の分からないものになってしまった、
と言う事です。つまり、プログラムも動画も目的を果たしていない例です。

TRさんは最初から勘違いしているようですが、ADRESはPWMとは関係ありません。
ADC変換の結果を格納するレジスタです。
PWMと連動させるなら全く別のプログラムになります。つまり点滅の速さではなく、
明るさを変えるプログラムです。

そして、内容をもっと考えてください。
点滅のスピードは単にADC値を何倍(x○秒)を変えるだけです。
意味が解っていれば

RB3=1;
for(i = 0; i<tmp; i++){__delay_ms(2);}
RB3=0;
for(i = 0; i<tmp; i++){__delay_ms(2);}



RB3=1;
for(i = 0; i<tmp; i++){__delay_us(20);}
RB3=0;
for(i = 0; i<tmp; i++){__delay_us(20);}

も同じ(意味)のスケッチだと判る筈です。

また、
>先頭で、まだADCを始めてさえいないのに
の部分は

while(ADCON0bits.GO_DONE); //変換完了待ち
return (Value);
の間で値を取得しないと意味がない、と言う事です。



追記しておきます。
ADCの結果を確認するプログラムなら、ます、ちゃんとその結果が大まかにでも確認できる、
というのが重要です。
つまり、ADCは10ビット、つまり、0〜1023までの結果になります。
RB3=1;
for(i = 0; i<tmp; i++){__delay_ms(2);}

と書いているのは最大値を取得した時に約2秒程度(点滅周期では4秒)を想定しています。
で、ボリュームを半分にした時が1秒、つまり、その程度なら時計などで、判断付きやすい、かつ、それほど時間がかからない、
というのを想定したものです。更にはマイコンが想定しているクロックで動作しているか確認できます。
それとも
> 案1は、遅すぎです。
は点滅間隔が20秒や30秒かかったということでしょうか?
もしそうなら他に原因があるのかも知れません。動作クロックが違ったとか。


動画をみてどの位の速さ、つまりADCの値が幾つ位で、ボリューム位置がどの位置にあるのか、点滅を見て判断付きますか?
この位置なら、この位、というものを実証している動画には見えません。
猛牛ロック   2018/11/18(Sun) 19:23 No.1222 記事編集
Re: ADRES
関数を無くし、意味不明な__delay_us(20); //アクィジョン時間 20usを無くし、
それと、読み取り値の変数宣言をValueからADRESにしました。
簡単にしました。
本当は、ADRESが変わったらといったif文も付けるのでしょうけど。


案1
for(i = 0; i<ADRES; i++){RB3=1;}
__delay_ms(2);
for(i = 0; i<ADRES; i++){RB3=0;}
__delay_ms(2);


案2
for(i = 0; i<ADRES; i++){__delay_ms(2);}
RB3=1;
for(i = 0; i<ADRES; i++){__delay_ms(2);}
RB3=0;


案1と案2の違い
案1は、iを0からADRESの値になったら、RBを点灯し、2msおいて、またiが0からADRESまでRBが点灯
案2は、iを0からADRESの値になったら、2msおいて、RBを点灯(またiが0からADRESになり、2ms経過するまでの間)し、次に、RBが消灯

どちらも同じに思えるが、周期は案1の方が早い。

結局、何故、案1が早くなるのか分かりませんでした。


while (1)
{
ADCON0bits.GO_DONE= 1; //AD変換開始
while(ADCON0bits.GO_DONE); //変換完了待ち
ADRES=(ADRESH<<8)+ ADRESL;
//※ここから案1と案2を入れ替えます。
for(i = 0; i<ADRES; i++){RB3=1;}
__delay_ms(2);
for(i = 0; i<ADRES; i++){RB3=0;}
__delay_ms(2);
}



追記

PWM機能とADC機能 よく理解せずに、今回、続けて読んできてしまった。

どちらも10ビット操作という点で似ていた。
これが、、、、間違えてしまった原因。

どちらも、Lチカなので、より一層困惑してしまった。


PWMは、CCPR1の上位8ビットとCCP1CONのDC1Bの2ビット
ADCは、上位8バイトがADRESH (ADRES High byte)、下位2バイトがADRESL

Lチカしたい場合、ADC変換時間を利用するのではなく、PWM機能でする。


while(ADCON0bits.GO_DONE); //ADCの変換完了待ち 、これを使うのではなく、
ADRESH + ADRESLのビットの値 =CCP1LとCCP1CONのDC1B
にすれば、OKと思われる。


どうでしょうか??

TR   2018/11/19(Mon) 11:23 No.1223 記事編集
Re: ADRES
まず、聞きたいのはTRさんは、いったい何をしようとしているのでしょうか?
案1も案2もプログラム的には間違いではありません。
なので、両方ともにかかれたように動きます。
重要な事は、目的と合致しているかどうかです。

> 読み取り値の変数宣言をValueからADRESにしました。

それはあまりいい変更ではありません。
というのはレジスタ名とダブル可能性があるからです。
(つまり、自分で作る変数に今回無いレジスタでもPORTDとかを付けるのはどうでしょうか?)
小文字にしておくとか区別した方が良いです。


> 何故、案1が早くなるのか分かりませんでした

orz 時間の計測の仕方をちゃんと覚えた方が良いです。
重要なのは「早くなる/遅くなる」ではなくて、それが○秒になる、と把握する事です。

Arduinoなら、時間をそのままPCに送って表示出来ますけど、
PIC使いならLEDの点滅の速さで識別するような使い方も覚える必要があります。
※でなければ、LCDや7セグを繋いで数値を表示させます。

ADCが5V、つまり、1023の時の時間を付けておきます。
なぜ、その時間になるのかを考えてください。
(説明は複数回しています)


for(i = 0; i<ADRES; i++){RB3=1;}//18.7ms
__delay_ms(2);//2ms
for(i = 0; i<ADRES; i++){RB3=0;}//18.7ms
__delay_ms(2);//2ms

これだと、約21msの点灯/消灯です。
実際の所、__delay_ms(2);は付けないで、ADRES*30とかの方が、まだ、比例関係になります。


for(i = 0; i<ADRES; i++) {__delay_ms(2);}//2.06s
RB3 = 1;//3us
for(i = 0; i<ADRES; i++) {__delay_ms(2);}//2.06s
RB3 = 0;//3us

こっちだと約2.06sの点灯/消灯です。
猛牛ロック   2018/11/19(Mon) 15:37 No.1224 記事編集
Re: ADRES
レジスタはともかく、PWMは出力です。目で見える状態としては点滅では無く点灯です。
LED照明などでの明るさ調整でも使われている手法です。
また、モータの速度調整にもよく使われています。

一方、ADC=アナログ/デジタルコンバータは入力したアナログ電圧を数値化するものです。
Lチカとは直接は関係ありません。
今回のように、ボリュームを付けた装置だと、ボリュームの位置が何処にあるのかを調べるために使います。
そして、そのボリューム位置が意味する出力?にします。
猛牛ロック   2018/11/19(Mon) 17:55 No.1225 記事編集
Re: ADRES
>まず、聞きたいのはTRさんは、いったい何をしようとしているのでしょうか?

有難うございます。
教科書でのPWMについては、半固定抵抗器を使っての明るさ調整がありませんので、
学習したいと思っています。

>というのはレジスタ名とダブル可能性があるからです。

止めます。


>重要なのは「早くなる/遅くなる」ではなくて、それが○秒になる、と把握する事です。

これからの、学習テーマの1つにしたいと思います。

自分で、PWM機能により可変抵抗器を使いLEDを滑らかに明るくしたり暗くしたりを考えましたが、
コンパイル不可
出来ましたら、ご指摘願いたいと思います。



/*PWM機能によりRB3のLEDで滑らかに調光。可変抵抗で制御*/
// 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)
#include <xc.h>
// クロック周波数指定
// (__delay_ms()関数が必要としているため)
#define _XTAL_FREQ 1000000
// プロトタイプ宣言
void InitPWM (void);
void InitTimer2 (void);
unsigned int adconv(void);
// メイン関数
void main (void)
{
OSCCON = 0x40; //クロック周波数を1MHzに設定
// 1,2,17,18端子を入出力端子に設定
CMCON = 0x07;
// 電圧レベルの初期設定
PORTA = 0xFF;
PORTB = 0xFF;
// 入出力設定
TRISA =0b00000001; // RA0(AN0)はアナログで読み取りピン(入力)
TRISB =0x00;
ANSELA=0b00000001;//RA0をアナログピンに設定
ANSELB=0x00; //
// ADコンバータ設定
ADCON0 = 0b00000001; // RA0をADコンバータピンにし、ADコンバータ機能をEbableに
ADCON1 =0b10000000; // 結果数値は右寄せ、ADコンバータクロックはFOSC/2、基準電圧はVDD
//変数宣言
unsigned int num ;
// PWMモード設定関数の呼び出し
InitPWM();
// タイマ2設定関数の呼び出し
InitTimer2();

while(1) {
// アナログ値の変換と読込み処理
adconv();
num = adconv(); //RA0から電圧を読み込んだ値をtempをnumに代入
CCPR1L = num/4 ; // 4で割って上位8ビットを取り出しアナログ値からのデータでデューティ値を設定
}
}
// アナログ値の変換と読込み処理
unsigned int adconv()
{
unsigned int temp;
ADCON0bits.GO_DONE= 1; //AD変換開始
while(ADCON0bits.GO_DONE); //変換完了待ち
temp = ADRESH ;//
temp = ( temp << 8 ) + ADRESL ;//RA0で読み込んだ値をtempに代入
return temp ;//読み込んだtempをnumに返す
}

// PWMモード設定関数
void InitPWM (void)
{
// RB3端子を出力端子に設定
TRISBbits.TRISB3 = 0;
// CCPのモードをPWMモードに設定
CCP1CONbits.CCP1M3=1;
CCP1CONbits.CCP1M2=1;
CCP1CONbits.CCP1M1=0;
CCP1CONbits.CCP1M0=0;
// 周期を1μ秒に設定(99 + 1μ秒)
PR2 =100;
// デューティーサイクルを0msで初期化
CCPR1L = 0;
CCP1CONbits.CCP1X=0;
CCP1CONbits.CCP1Y=0;
}
// タイマ2設定関数
void InitTimer2 (void)
{
// プリスケーラ値を1に設定
T2CONbits.T2CKPS1=0;
T2CONbits.T2CKPS0=0;
// TMR2レジスタをクリア
TMR2 = 0;
// タイマ2起動
T2CONbits.TMR2ON= 1;
}
TR   2018/11/19(Mon) 18:43 No.1226 記事編集
Re: ADRES
動作しました!
可変抵抗器で明るくなったり暗くなったりしました。
間違いを
MPLABが教えてくれました。

変更点
ANSELA →ANSEL
ANSELB → この行を削除

でも、ANSELにはAかBを付ける必要と思うのですが。
どうしてだろう?


と思って、、データシートを見ると、
88にはANSELはAがわの0〜7までしかありませんでした!!
TR   2018/11/19(Mon) 19:14 No.1227 記事編集
Re: ADRES
> while(1) { // アナログ値の変換と読込み処理
> adconv();
> num = adconv(); //RA0から電圧を読み込んだ値をtempをnumに代入
> CCPR1L = num/4 ; // 4で割って上位8ビットを取り出しアナログ値からのデータでデューティ値を設定
> }

の部分ですけど、adconv();を2回しています。
これ自体、間違いで残ったのだと思うのですけど、実際に複数のアナログ入力ピンを切り替えて使う時に
この手法を取ったりします。(1回を読み捨てる)
つまり、切り替えてすぐに取得すると間違った値になりやすいからです。
で、前に、

> 意味不明な__delay_us(20); //アクィジョン時間 20usを無くし

と言っていますけど、これもチャンネルを切り替えた後に、その電圧が安定するまで少し待っている、という意味だと思います。
今回はチャンネルを切り替える訳では無いので、無くても大丈夫かな?と思っています。


> // 周期を1μ秒に設定(99 + 1μ秒)
> PR2 =100;

以前もおかしな記述(コメント)があったのですけど、取りあえず放っておきました。
それは

> // 周期を1μ秒に設定(249 + 1μ秒)
> PR2 =249;
というものです。
この時の周期は(249+1)*4[us]=1000[us]=1msです。

で、今回の場合は
(100+1)*4=404usです。


あと、PWMやADCのメカニズム?をちゃんと押さえておいた方が良いです。
PWMだと、
PR2が周期、つまりこの値が上限に当たります。
duty値がHIGH→LOWに切り替わる値です。(場合によっては逆側に切り変える設定があったりもします)
タイマーが0で出力がHIGHになり、タイマーがduty値でLOWに切り替わります。
「249」と、250に1を引いた数にするのは249をカウントして、次の0になった時にHIGHになるので1を引きます。

そうした仕組みなので、PR2を101(101/255)にして、ADCの値をそのまま入れてもボリュームの半分以下の部分しか
反応しない(つまり、101/255以上になると常にHIGH)になっていると想像します。
感覚的にはどうだったでしょうか?
ボリュームのフルレンジを使って、明るさを調節したいのなら、PR2は255が適当でしょう。
勿論、ADCの値に101/255をかけたものをduty値に設定しても良いですけど。


で、
while(1) { // アナログ値の変換と読込み処理
num = adconv(); //RA0から電圧を読み込んだ値をtempをnumに代入
CCPR1L = num/4 ; // 4で割って上位8ビットを取り出しアナログ値からのデータでデューティ値を設定
}
の部分だと1回で、280us程度の時間しかかかりません。つまり、PWMの1回の点滅よりも多く取得して、
切り替え値を操作しています。
そう言った時は適度なディレイを入れた方が良いと思います。(そのままで駄目という訳では無いですけど)
つまり、
while(1) {
num = adconv();
CCPR1L = num/4 ;
__delay_ms(10);
}
程度にするのが適当かな、と思う次第です。
で、これを書き換えると(まぁ、書き換えなくても良いのですけど)

while(1) {
CCPR1L = adconv()/4 ;
__delay_ms(10);
}

で、同じ意味です。
それが、No.1213で書いたArduinoの
void loop() {
analogWrite(3,analogRead(A0)/4);
delay(10);
}
です。こっちのdelay(10);も同じ意味で付けています。
猛牛ロック   2018/11/20(Tue) 02:50 No.1228 記事編集
Re: ADRES
> while(1) { // アナログ値の変換と読込み処理
> adconv();
> num = adconv(); //RA0から電圧を読み込んだ値をtempをnumに代入
> CCPR1L = num/4 ; // 4で割って上位8ビットを取り出しアナログ値からのデータでデューティ値を設定
> }

の部分ですけど、adconv();を2回しています。
これ自体、間違いで残ったのだと思うのですけど、実際に複数のアナログ入力ピンを切り替えて使う時に
この手法を取ったりします。(1回を読み捨てる)


そのとおりです。1回を読み捨てるという内容です。
この意味合いで使いました。
であれば、OKですよね。

以前、間欠プログラムでも似たような以下や、あちこち見ていて、このアイデアを思いつきました。
可決プログラムから抜粋 ↓
// 永久ループ
while(1){
MODE=PORTA&0b11;
__delay_ms(50);
while(MODE!=(PORTA&0b11)){ //変化があればウェイト、無ければ確定
MODE=PORTA&0b11;



> 意味不明な__delay_us(20); //アクィジョン時間 20usを無くし

と言っていますけど、これもチャンネルを切り替えた後に、その電圧が安定するまで少し待っている、という意味だと思います。
今回はチャンネルを切り替える訳では無いので、無くても大丈夫かな?と思っています。


そうでしたか。チャタリング防止ですね。


> // 周期を1μ秒に設定(99 + 1μ秒)
> PR2 =100;

以前もおかしな記述(コメント)があったのですけど、取りあえず放っておきました。



この方法は、キットで遊ぼうの教科書にありました。
写真参照願います。
教科書では、周期を先に100μsとして、PR2を逆算しています。
ただ、プログラムの方は「周期を1μ・・・」となってしまっていましたので、間違えです。教科書では100μsです。

今回のように可変抵抗器で調光する場合、周期やPR2はどのように考えて決めるのでしょうか?



自分なりに思うと、
写真の公式によれば、
周期=(PR2+1)1/(動作処理速度÷4)
となっているので、
動作処理速度 1MHz(とりあえずにした値です)
100μs=(PR2+1)1/(1MHz÷4)
100×4/1-1=PR2
従って PR2=309μs

なので、動作を先に確認したかったので、PR2=100 としましたが、
本当は、309μsでした。
で、今直しました。
今のところ、LEDの状況を見ると、不満は、
VRを絞りると暗くなるけど、
明けきらない内に、頭打ちになって明るさが伴っていない感じです。
解消方法は有りますか?


以下に説明されていますが、文字だけでは、自分には良く分かりません。
もう少し、おいおい、なんとかしたいと思ってはいます。キットで遊ぼうの教科書を、今回のご指摘を踏まえて再度読み込んでみます。
1週間前まではチンプンカンプンでしたから、自分でもよくここまで来たかと思っているところです。
申し訳ありません。


ところで、250という数字が出てきますね。
255が適当でしょうとの事ですね。
周期を255にするPR2を逆算してプログに反映してみます。



> // 周期を1μ秒に設定(249 + 1μ秒)
> PR2 =249;
というものです。
この時の周期は(249+1)*4[us]=1000[us]=1msです。

で、今回の場合は
(100+1)*4=404usです。


>あと、PWMやADCのメカニズム?をちゃんと押さえておいた方が良いです。
PWMだと、
PR2が周期、つまりこの値が上限に当たります。
duty値がHIGH→LOWに切り替わる値です。(場合によっては逆側に切り変える設定があったりもします)
タイマーが0で出力がHIGHになり、タイマーがduty値でLOWに切り替わります。
「249」と、250に1を引いた数にするのは249をカウントして、次の0になった時にHIGHになるので1を引きます。

そうした仕組みなので、PR2を101(101/255)にして、ADCの値をそのまま入れてもボリュームの半分以下の部分しか
反応しない(つまり、101/255以上になると常にHIGH)になっていると想像します。
感覚的にはどうだったでしょうか?
ボリュームのフルレンジを使って、明るさを調節したいのなら、PR2は255が適当でしょう。
勿論、ADCの値に101/255をかけたものをduty値に設定しても良いですけど。


>で、
while(1) { // アナログ値の変換と読込み処理
num = adconv(); //RA0から電圧を読み込んだ値をtempをnumに代入
CCPR1L = num/4 ; // 4で割って上位8ビットを取り出しアナログ値からのデータでデューティ値を設定
}
の部分だと1回で、280us程度の時間しかかかりません。つまり、PWMの1回の点滅よりも多く取得して、
切り替え値を操作しています。
そう言った時は適度なディレイを入れた方が良いと思います。(そのままで駄目という訳では無いですけど)
つまり、
while(1) {
num = adconv();
CCPR1L = num/4 ;
__delay_ms(10);
}
程度にするのが適当かな、と思う次第です。
で、これを書き換えると(まぁ、書き換えなくても良いのですけど)


分かりました。


>while(1) {
CCPR1L = adconv()/4 ;
__delay_ms(10);
}

で、同じ意味です。
それが、No.1213で書いたArduinoの
void loop() {
analogWrite(3,analogRead(A0)/4);
delay(10);
}
です。こっちのdelay(10);も同じ意味で付けています。


分かりました。


追記
周期255にしてPR2を1019にしたら、
調光の具合は良いです。

TR   2018/11/20(Tue) 07:44 No.1229 記事編集
Re: ADRES
> そうでしたか。チャタリング防止ですね。
いいえ、そうではありません。
大抵のマイコンは、ADCの装置は1つで、それを複数のピンにADC装置の外側で、マルチプレクサで切り替えて使います。
それで複数のピンでADCを使えるようにしています。
で、接続ピンを切り替えるという事は異なる電圧に繋がる、という事です。その際の誤計測の防止の為に。1回読み飛ばしたり、ちょっと間を空けたりします。


そのテキストでは4MHz駆動=1MHzサイクル=1us/カウントでPR2が99なので
(99+1)*1us=100usです。

最初の例では1Mhz駆動=250kHzサイクル=4us/カウントで、PR2が249です。なので、
(249+1)*4=1000us=1msです。

今回のものも1Mhz駆動=250kHzサイクル=4us/カウントで、PR2は100です。なので
(100+1)*4=404us
となります。マイコンの速度は元になる駆動クロックから求まります。

※カウント数と1サイクル(カウント)時間をかけた方が分かりやすいと思います。


> 可変抵抗器で調光する場合、周期やPR2
まず、ボリュームによるADC入力と、PWM出力の間に関連性はありません。
「スイッチを押したらLEDを点灯させる」というものが、元々スイッチとLEDという無関係の物を
連動させているのと同じです。

LEDの適正周期に関してはマイコンとはあまり関係ありません。
人間にとって100Hz=10msよりも周期が長いとちらつきを感じると言われています。
なので、7セグ等はそれよりも短いものにします。
照明で利用するなら更に周期を短くする必要があるでしょう。
※周波数が高すぎて問題が起こることは殆どありません。ただし、周波数が高いほどノイズを誘発し易くなる事、
波形が乱れやすくなることがあります。

で、ボリュームの指している値、つまり、抵抗値の割合とPWMのduty比を一致させる、という考えもあります。
そうするとボリュームとLEDの電力が比例関係になります。


上で説明した通り、まず、カウンタの動作を考えてください。
カウンタがPR2の値になると0に戻ります。つまり、0→PR2を繰り返すカウンタです。
そして、duty値とカウント値を比較して、どちらが大きいかで、HIGH/LOW出力が決まります。。
duty値が大きすぎてPR2以上なら何も変化せずに、HIGH出力です。

時間や表示を最優先にしたいなら、周期(PR2+1)は10進数できりが良い値でしょうね。
100や250が適当だと思います。例えば%表示をしたい場合などはそのまま100でいいでしょう。
ADCが最大1023なので、
<ADC>*100/1023の計算をしてduty値のレジスタCCPR1Lに入れて、表示させることになります。
ただし、余りがでるのでちょっと嫌な感じがします。
※ADCが0〜10が0、11〜20が1、…と殆どの範囲が10になるのですけど、MAX100の範囲は1023のみになります。
そうなるのを避けるために、<ADC+50>*100/1023とする手法もあります。

ボリュームとPWMを同期させるなら0xFFが良いです。
ADC値を4で割ればそのまま使えます。つまり、割り切れます。


> 周期255にしてPR2を1019にしたら、
意味が判りません。PR2レジスタは8ビットなので、そのまま
PR2=0xFF;//又はPR2=255;
です。
PR2=1019;
と、入りきらない値を書くと上位桁が消されて
PR2=251;//1019%256=251
と同じ意味になります。

※ちなみに、PWMは10ビットですけど、下位2ビットはプリスケーラを使います。
なので、プリスケーラが1:1の今回の場合は実質的に切り捨てられるような気がします。
詳しくはデータシートで確認して下さい。

上記はプリスケーラが1:1のときはプリスケーラではなく、駆動クロックが代わりになるようです。
なので、10ビットのPWMになるのは変わらない、という事でした。
猛牛ロック   2018/11/20(Tue) 12:15 No.1230 記事編集
Re: ADRES
こんばんは。
今日も、MPLABさんのPWMとADコンバーターの記事を読んできました。
少しは分かったような感じがします。


No1229
>で、
@ while(1) { // アナログ値の変換と読込み処理
A num = adconv(); //RA0から電圧を読み込んだ値をtempをnumに代入
B CCPR1L = num/4 ; // 4で割って上位8ビットを取り出しアナログ値からのデータでデューティ値を設定
}
の部分だと1回で、280us程度の時間しかかかりません。


280μsとは、@+A+Bのプログラム内容をPICがこなす時間ですか?
MPLABIDXのシュミレーター機能を使えば、プログラムの作業時間が分かるのかな?
やってみたけど、難しい。

尚、__delay_ms(10);は追加しました。



No1230
>※ADCが0〜10が0、11〜20が1、…と殆どの範囲が10になるのですけど、MAX100の範囲は1023のみになります。
そうなるのを避けるために、<ADC+50>*100/1023とする手法もあります。

良く分からないので、PR2は249μsにしました。
PWMの操作とは、内蔵クロックなどを基本に、端子から読み取ったアナログ電圧とを比べての操作になるんでしょう。
今は、これくらいにします。



No1230
>※ちなみに、PWMは10ビットですけど、下位2ビットはプリスケーラを使います。
なので、プリスケーラが1:1の今回の場合は実質的に切り捨てられるような気がします。
詳しくはデータシートで確認して下さい。


DutyCycleを決める10ビットの内、下位2ビット(CCP1CONレジスタのDC1Bビット)
この事ですか?


ともかく、ここまでプログラムを組めるようになったので嬉しいです。
TR   2018/11/20(Tue) 20:58 No.1231 記事編集
Re: ADRES
「1回で」、というのはAとBという意味です。
勿論それは駆動クロックによって大きく変動します。
シミュレータで以前調べたのを利用して換算しました。
今回、直接調べた訳では無いです。
以前調べた時は4MHz動作の時にADC変換が68usだったと思います。
その4倍位です。Bは2サイクル=8us程度でしょう。

> PWMの操作とは、内蔵クロックなどを基本に、端子から読み取ったアナログ電圧とを比べての操作になるんでしょう。
だから、PWMとADCは、全くの別物です。ADCは電圧計です。PWMは高速の点滅です。
今回はそれを組み合わせただけです。まぁ、そういった使い方もよくあるとは思いますけど。

ただ、今まで言いませんでしたけど、ADCや時間と比例関係で動作させるのではなく、累乗?のようにすることもあります。
つまり、8段階の明るさとして、均等の32、64、96、128…256ではなく、2,4,8,16…256のように進行させたりします。
均等割りだと急に明るくなり、明るい部分ではあまり変化が感じません。逆に暗い部分は急に変化しているように感じます。


100分割(%)の計算「<ADC>*100/1023」だと、判り難いのでこれを4分割の式にしてみると「<ADC>*4/1023」になります。
でもこの計算式だとADCの値が0〜255だと0です。256〜511が1です。512〜767が2です。768〜1022が3です。そして、1023だけが4になります。
まぁ、今回の事とはあまり関係ない話です。

> DutyCycleを決める10ビットの内、下位2ビット(CCP1CONレジスタのDC1Bビット)
> この事ですか?

そうです。その比較対象のタイマーの方です。
タイマーのその部分はTIMER2のカウント外です。なので、カウントしている数値は読み出せません。
プリスケーラのカウンタ部分が使われている、というのをうろ覚えしていたのですが、
1:1ということはプリスケーラが使われていません。
なので、TIMER2のみで比較しているのでは?と思ったのですが、駆動クロックが利用されている、という記述を見つけました。
duty値の下位2bitも有効です。
上限(周期)が上位8ビット指定で、比較(duty値)は10ビット指定、という点は判り難い構成ですね。
そして、本体となるタイマーも下位2ビットは見えない部分で作られています。
猛牛ロック   2018/11/20(Tue) 22:56 No.1232 記事編集
Re: ADRES
下の@〜Bのプログラム実行時間が分かりまし。
122μsだと出ました。

while(1) {
// アナログ値の変換と読込み処理
@ adconv();
Anum = adconv(); //RA0から電圧を読み込んだ値をtempをnumに代入
BCCPR1L = num/4 ; // 4で割って上位8ビットを取り出しアナログ値からのデータでデューティ値を設定
__delay_ms(10);


それで話しついでですが、
猛牛ロックさんが言われていることで、PICの欠点ですが、
少し分かってきました。

ADコンバーターには速さの設定が有ります。
合成写真右側です。
早い方が良いと思いますが、一番早いのは、2Toscですか?

単純に2Toscを選んでよいのでしょうか?

TR   2018/11/21(Wed) 15:39 No.1233 記事編集
Re: ADRES
> 早い方が良いと思いますが、一番早いのは、2Toscですか?

勿論、早い方が良いと言えますけど、信頼性との兼ね合いもあります。
また、計測の回数が増えるほど、他の作業の邪魔になる場合もあります。
まぁ、今回の場合は、
> while(ADCON0bits.GO_DONE); //変換完了待ち
とウェイトしていますから、早い方が良いですね。
今回のようなウェイトする場合と、完了→割り込みをする場合があります。

で、今回(1MHz駆動)の場合、設定上一番早いのは、2Toscになります。
もし、4MHz駆動にした場合は8Toscです。
だけども、それよりも1つ2つ遅くした方が賢明だと思います。
私自身は測定出来るぎりぎりのラインは使いません。
猛牛ロック   2018/11/21(Wed) 18:01 No.1234 記事編集
Re: ADRES
>だけども、それよりも1つ2つ遅くした方が賢明だと思います。
私自身は測定出来るぎりぎりのラインは使いません。

分かりました。



今は、内部クロックが1Mhzです、
これをもっと早くすれば、全体の速度は早くなるのですか?


それと、No1223の写真にあるデータシートの注意書きをグーグル翻訳をしたら ↓
注1:RCソースの標準TAD時間は4μsですが、2~6μsの間で変化する可能性があります。

あるサイトで見つけました。


 TAD=(PICクロックの周期)×(Tosc)

今回は、OSCCON = 0x40; //クロック周波数を1MHzに設定 →1μs
Toscは、現在、2Toscなので、No1223写真のデータシートにより
1.25Mhz → 0.8μs

Tosc=1μs × 0.8μs
Tosc=0.8  となってOkでしょうか?

とおもったら、
Operationの方を掛けるのですか?
TR   2018/11/21(Wed) 19:26 No.1235 記事編集
Re: ADRES
御免なさい。間違った事を書いてしまいました。

基本は1.6us〜6.4usの間になるように選択する、と言う事みたいです。
なので、1MHz駆動(1us周期)の場合は、2TOSCか4TOSCのどちらかにする、と言う事になると思います。
より推奨されるのが4usになる4TOSCなのでしょうけど、2TOSCでも全く問題はないと思います。
※つまり、2TOSCの選択はギリギリという事ではなく、推奨される範囲の値、という事。

また、一番下のRCを選択しておくのが無難だとも感じました。これはおおよそ4usになるRCです。
これを選択しておけば、1MHz駆動のソースでも、4MHz駆動のソースでも共通で済みます。
また、sleepという機能を使った時にADC変換を行いたい時にはこのRCをを選択している必要があります。
※自分なりにデータシートを読み取った感想ですが、確証はありません。
猛牛ロック   2018/11/22(Thu) 00:00 No.1236 記事編集
Re: ADRES
パソコンでも、クロック数は、大きい方、2Mhより4Mhzといった具合。
PICも内蔵クロック数を大きく設定した方が、PICの動作速度が速くなるのでしょうか?
今は、1Mhzに設定。


TAD=(PICクロックの周期)×(Tosc)
この式は合っていたようですね。

追記
時期PICはやはり、日本語のデータシートがあった方が良いですね。
16F1823  これに近い奴16F1827
http://akizukidenshi.com/catalog/g/gI-04430/

であれば、
TAD=1μs×2Tosc
TAD=2μs
でもRCといった選択肢があったわけですね。
有難うございます。


日本語のデータシートがあるPIC16F1823が欲しい。
TR   2018/11/22(Thu) 07:19 No.1237 記事編集
Re: ADRES
速度の考え方は、PCと同じです。
通常、4MHz駆動なら1MHz駆動の4倍速く動いていますから、1MHz→4MHzとすると
動作時間が1/4になります。

ただし、今回のようにADCは、ADCの変換速度はある範囲内、つまり一定にしてほしい、と言う事です。

> TAD=(PICクロックの周期)×(Tosc)
> この式は合っていたようですね。
いいえ、
(PICクロックの周期)と(Tosc)は同一です。
Fosc「周波数」=1/Tosc です。
で、
TADを「1.6us〜6.4usの間になるように」倍率を選択する、と言う事です。
1MHz駆動ならToscは1usです。そして設定できる倍率は、1,2,4,8、…なので、
2か4を選択する事になります。

RCはただ選択するだけです。計算はありません。おおよそ4usが標準値になるように作られているけども、
2〜6usのアバウトの範囲としか保証しない、と言う事です。


追記
16F1827だと、ちょっと性能が上がって、推奨範囲が広がっています。
数値は見つけられなかったですけど、例えば、0.8us〜6.4usのように速い速度のほうが広がったのだと思います。
なので、TADが1usも推奨範囲になっていますね。
そして、RCの標準値も1.6usになっています。
猛牛ロック   2018/11/22(Thu) 08:40 No.1238 記事編集

- JoyfulNote v6.02 -
++ Edited by Hamel ++