PIC12F683のULPW機能を使った電力制御について

このQ&Aのポイント
  • PIC12F683の機能のUltra Low-Power Wake-upを使用して電力制御を行う方法について説明します。
  • 質問者はGP0に抵抗とコンデンサを接続して動作させ、オシロでの波形確認も行ったが、しばらくするとGP0がHiのままになる現象に遭遇している。
  • GP0がHiのままになる現象についての情報を求めている。
回答を見る
  • ベストアンサー

PIC12F683 のULPW機能につきまして

PIC12F683の機能のUltra Low-Power Wake-up の機能使おうとこちらhttp://www.picfun.com/pic26.htmlを参考にさせていただいて、GP0に抵抗と、コンデンサをR=200Ω、C=0.1μFで動かしてみました。 取りあえずは動作した(オシロできちんとのこぎりの波形を確認でました)のですが、しばらくすると、GP0がHiの状態のままになってしまいます。 このような現象を経験された方はいないでしょうか? 情報があれば助かります。 この動作を行うためのプログラムは以下のようにしてみました。 (MikroCを使っています) *****************************************************/ #define _ON 1 #define _OFF 0 #define _INPUT 1 #define _OUTPUT 0 #define SIG GPIO.F1 #define PWR GPIO.F5 void interrupt() { // 全体割り込み停止しているので、GPIO.1pin に変化があっても、ここの関数は呼び出されない if (INTCON.GPIF) { INTCON.GPIF = 0; // Port Change Interrupt Flag clear // GPIO.F1 = 1; // delay_ms(700); // 700ms LED ON // GPIO.F1 = 0; } } void opl_sleep() { INTCON.GIE = 0; //全体割り込みは停止 IOC = 0b00000001; // Interrupt pin GP0 only //1pinだけ検知する。 INTCON.GPIF = 0; // Port Change Interrupt Flag clear INTCON.GPIE = 1; //Enables the GPIO port change interrupt //ポート割り込み有効にすればsleepから復帰 TRISIO.F0 = _INPUT; // Input PCON.ULPWUE = _ON; SIG = _OFF; // Low sleep_start: asm{ nop nop nop nop sleep nop nop nop nop } INTCON.GPIE = 0; // disable GPIO port change interrupt INTCON.GPIF = 0; // Port Change Interrupt Flag clear //場合によっては、ここにチャタリング処理(wait)を入れると良い // INTCON.GIE = 1; } void _FloatValToStr( float val, char* str ) { unsigned char ch = 0x00; int val2; val2 = val * 1000; // val2 = val; ch = (val2 / 1000) % 10; // extract 1.0 volts digit str[0] = 48+ch; // write ASCII digit at cursor point str[1] = '.'; ch = (val2 / 100) % 10; // extract 0.1 volts digit str[2] = 48+ch; // write ASCII digit at cursor point ch = (val2 / 10) % 10; // extract 0.01 volts digit str[3] = 48+ch; // write ASCII digit at cursor point ch = val2 % 10; // extract 0.001 volts digit str[4] = 48+ch; // write ASCII digit at cursor point str[5] = 0x00; } void _CheckADC() { short i; double adc; double val = 0; char str[10]; //センサー信号取り込み ( Vref=3.0V : 実測値 ) adc = Adc_Read(2); val = (double)( adc * 300 ) / 1023; val = val / 100; // _FloatValToStr( val, str ); if ( val > 2.5 ) { // センサーに圧が掛かった! PWR = _ON; Delay_ms( 2000 ); PWR = _OFF; } } void main() { unsigned int co; ANSEL = 0b00100; // Configure AN pins as digital // CMCON = 7; // Turn off the comparators OSCCON = 0b01110000; // クロックを8Mhzに設定する。 CMCON0 = 0b00000111; // コンパレータ使用しない PCON = 0b00100000; // Ultra Low-Power Wake-up enabled TRISIO = 0b00000101; //GP0 pin input GPIO = 0; OPTION_REG.NOT_GPPU = 0; //GPIO pull-ups are enabled //内部弱プルアップに設定する WPU = 0b00000001; //PULL-UP REGISTER setting ,only GP0 pull-up SIG = _OFF; while( 1 ) { TRISIO.F0 = _OUTPUT; // Output GPIO.F0 = _ON; // Hi delay_ms(10); /*** for(co=0;co<10;co++){ //500ms だけLEDをピカピカッとやる GPIO.F1 = ~GPIO.F1; delay_ms(50); } **/ opl_sleep(); //SLEEPへ SIG = _ON; _CheckADC(); delay_ms(40); } }

質問者が選んだベストアンサー

  • ベストアンサー
  • koujikuu
  • ベストアンサー率43% (428/992)
回答No.2

当方 PIC12F683 の手持ちが無いので試験できません ULPWU割り込みは、ポート変化割り込みを利用しています、割り込み発生時にGPIOのリードを行わないと連続して割り込みがかかります、(割り込み条件を満たしている為、INTCON.GPIF フラグが解除されない) 参照 (PORTBピン変化割込みとは) http://homepage3.nifty.com/mitt/pic/pic1320_08.html GP0=H 出力ポートに設定して外部コンデンサを充電してからGPIOのリードを行いポート変化割り込み条件の再設定を行います。

pop_ohshima
質問者

お礼

koujikuuさん、ご助言ありがとうございます。 解決しました。 原因は、やはりULPWUをインターバルとするSLEEP関数の部分の順番(手順)が違っていました。 GP0をOUTPUTしてHiを送りコンデンサに充電した後の処理で、GP0をINPUTにしてからULPWUEビットをONにしていたのがNGでした。 正しくは、GP0をINPUTにする前に、ULPWUEビットをON、IOCの0ビットをONにすることでうまく動作するようになりました。 Mikro-Cで書かれたULPWUのプログラムgた中々ないので後日、時間あればソースを公開させて頂きます。 ありがとうございました。

その他の回答 (1)

  • koujikuu
  • ベストアンサー率43% (428/992)
回答No.1

ULPWU機能は使用したことが無いので見当違いかも知れません GP0の弱プルアップ機能が有効になっているので、外部コンデンサが常時充電状態なのでは? (弱プルアップは、VDDとGP0に数KΩの抵抗が入っているのと同じ) データシート FIGURE 4-1: BLOCK DIAGRAM OF GP0 参照 http://akizukidenshi.com/download/ds/microchip/pic12f683.pdf

pop_ohshima
質問者

お礼

koujikuuさん、アドバイスありがとうございます。 弱プルアップしていましたので無効にしてみましたが、今度は、スリープ状態から抜けなくなりました。 一発目の充電からスリープに入って、そのまま帰ってこない状態です。 そもそも、当初に確認でした「のこぎり波」もきちんと出ていたのか不安になりました。

pop_ohshima
質問者

補足

その後、いろいろとやっていたら、どうやらASM命令のSLEEPで戻ってこないような感じでした。 ますます、どツボ状態です。

関連するQ&A

  • PICでのプログラミングについて教えて下さい。

    現在電圧計を製作していて4桁の7セグダイナミック点灯で行き詰っております(超初心者です)。 PICは16F873Aを使用、コンパイラはCCS、書き込みはピックライタ、あとシリアルデバッカを使用しています。 外部から電圧をかけそれをAD変換し、AD変換結果(0~5V)を7セグに表示させようとしています。 一応今の状態でも電圧表示はできていることはできているのですが一桁目から4桁目まで目で追えるくらい遅いスピードでこれを改善したいです。ソースは下記のソースを製作しました。この状態で3日間悩んでおります...知恵をお貸しいただけないでしょうか。 よろしくお願いします。 #include <16F873a.h> #device ADC=10 //A/D変換10bitモード #use fast_io(A) /* TRISレジスタの設定が必要 */ #use fast_io(B) #use fast_io(C) #use delay (clock=10000000) //10MHz #use RS232( BAUD = 9600, XMIT = PIN_C6, RCV = PIN_C7, PARITY = N, BITS = 8 ) #fuses HS,NOWDT,PUT,NOPROTECT,NOBROWNOUT,NOLVP #define VOLTAGE PIN_A0 // (in) #define CORRENT PIN_A1 // (in) #define VREF1 PIN_A2 // (in) #define VREF2 PIN_A3 // (in) #define RESERVE1 PIN_A4 // (out) #define RESERVE2 PIN_A5 // (out) #define LED_DP PIN_B0 // (out) #define LED_A PIN_B1 // (out) #define LED_B PIN_B2 // (out) #define LED_C PIN_B3 // (out) #define LED_D PIN_B4 // (out) #define LED_E PIN_B5 // (out) #define LED_F PIN_B6 // (out) #define LED_G PIN_B7 // (out) #define DIG_0 PIN_C0 // (out) #define DIG_1 PIN_C1 // (out) #define DIG_2 PIN_C2 // (out) #define DIG_3 PIN_C3 // (out) #define INI_TRIS_A_VAL 0x0F // 7:x 6:x 5:out 4:out 3in 2:in 1:in 0:in #define INI_TRIS_B_VAL 0x00 // 7:out 6:out 5:out 4:out 3out 2:out 1:out 0:out #define INI_TRIS_C_VAL 0x80 // 7:in 6:out 5:out 4:out 3:out 2:out 1:out 0:out int ct;//数字の更新間隔 long val;//表示する数字 int digit;//表示する桁 //表示パターン int segment_data[]={0x81,0xF3,0x49,0x61,0x33,0x25,0x05,0xF1,0x01,0x31}; char st[4]; void main() { float ata1,data2,data3,data4; long data5; long val; SET_TRIS_A( INI_TRIS_A_VAL ); SET_TRIS_B( INI_TRIS_B_VAL ); SET_TRIS_C( INI_TRIS_C_VAL ); setup_adc_ports(AN0_AN1_VSS_VREF); setup_adc(ADC_CLOCK_DIV_32); //Fosc/32 最高速度 digit=0; ct=1;//数字を更新する周期 val=0;//表示する値 while(1) { output_low(RESERVE2); //動作ランプ //////////////////////電圧測定///////////////////////////////// set_adc_channel(0); delay_us(50); //アクイジションタイム待ち(マイクロ秒) data1 = read_adc(); //AD変換結果読み込み printf("ADC V %9.3f \r\n", data1 ); //AD変換データ表示 data2 = (data1 * 4.959695) / 1024; //BCDに変換 printf("Volt %6.3f \r\n", data2 ); //変換データ表示 data5 = data2 * 1000 ; //data2を整数に変換 val = data5 ; printf("val %ld \r\n", val); //整数にし表示 /////////////////////7SEG表示////////////////////////////////// ct --; if(ct == 0){//数字の更新 st[3]=val/1000; //4桁目数値取り出し st[2]=val/100-st[3]*10;//3桁目数値取り出し st[1]=val/10-((st[3]*100)+(st[2]*10));//2桁目数値取り出し st[0]=val%10;//あまり val++; if(val==1000) val=0; ct=20; } if(digit== 3){//第4桁の表示 output_b( segment_data[st[3]]); output_bit(DIG_0,1);  //4桁表示開始 output_low(LED_DP);  //小数点表示  delay_us (5); //表示期間(ミリ秒) output_bit(DIG_0,0); //表示を消す output_high(LED_DP); //小数点を消す delay_us(50); //待ち(マイクロ秒) } if(digit== 2){ output_b( segment_data[st[2]]); output_bit(DIG_1,1); delay_ms (5); output_bit(DIG_1,0); delay_us(50); } if(digit== 1){ output_b( segment_data[st[1]]); output_bit(DIG_2,1); delay_ms (5); output_bit(DIG_2,0); delay_us(50); } if(digit == 0){ output_b( segment_data[st[0]]); output_bit(DIG_3,1); delay_ms (5); output_bit(DIG_3,0); delay_us(50); } digit ++;//表示桁を変更 if(digit ==4 ) digit=0; } }

  • 3桁7SEG時計(PIC16F648A)を作りた…

    3桁7SEG時計(PIC16F648A)を作りたい・・ 3桁時計を作りたいです。 割り込みを使って1秒を作って0:00から9:59まで表示する時計。 私はプログラムの方はあんまり得意ではないので、 ご教授の方よろしくお願いいたします。 以下、必要と思われる情報です。 Device:PIC16F648A マイクロチップテクノロジ コンパイラ:CCS社製PICC MATLAB+CCSコンパイラの環境です。 このハードウェアで0~999までカウント するプログラムは動作しています。 クロック:内臓4MHzです。 ハードウェアポート仕様 PORTA_A1:7SEGLED Cathode Common制御 分(1の位)NPNトランジスタON/OF    A2:7SEGLED Cathode Common制御 分(10の位)NPNトランジスタON/OF    A3:7SEGLED Cathode Common制御 時(1の位)NPNトランジスタON/OF PORTB_B0:7SEGLED Anode 制御 7SEG_a PORTB_B1:7SEGLED Anode 制御  7SEG_b PORTB_B2:7SEGLED Anode 制御  7SEG_c PORTB_B3:7SEGLED Anode 制御  7SEG_d PORTB_B4:7SEGLED Anode 制御  7SEG_e PORTB_B5:7SEGLED Anode 制御  7SEG_f PORTB_B6:7SEGLED Anode 制御  7SEG_g PORTB_B7:7SEGLED Anode 制御  7SEG_h 下記のプログラムは0~600までカウントするプログラムです。 val値でカウントする値を可変できます。 #include <16f648a.h> #fuses INTRC_IO,NOWDT,NOLVP,NOMCLR //内部クロック、WDT,LVPなし #use delay(CLOCK=4000000) //クロック4MHz //#define TIME_OUT unsigned int const LED_SEG[]=      //7SEG表示用テーブル { 0b00111111, /* 0= "0" [1] */ 0b00000110, /* 1= "1" [2] */ 0b01011011, /* 2= "2" [3] */ 0b01001111, /* 3= "3" [4] */ 0b01100110, /* 4= "4" [5] */ 0b01101101, /* 5= "5" [6] */ 0b01111100, /* 6= "6" [7] */ 0b00100111, /* 7= "7" [8] */ 0b01111111, /* 8= "8" [9] */ 0b01101111, /* 9= "9" [10]*/ 0b10000000,   /* 10= "." [11]*/ 0b01000000, /* 11= "-" [12]*/ }; unsigned int ct; //数字の更新間隔 unsigned long val; //表示する数字 unsigned int digit; //表示する桁 unsigned char st[3]; void main(void) { set_tris_a(0b11110000); set_tris_b(0b00000000); digit=0; ct=1; //数字を更新する周期 val=0; //表示する値 while(1) { ct --; if(ct == 0) { //数字の更新 st[2]=val/100; // st[1]=val/10-st[2]*10; //計算 st[0]=val%10; //計算 val++; if(val==600) val=0; ct=20;          //200にすると                          //約1秒間隔の表示に                          //なります。 } if(digit== 2) { //第3桁の表示 output_b(LED_SEG[st[2]]); output_bit(PIN_A3,1);//3桁表示開始 delay_ms (5); //表示期間(ミリ秒) output_bit(PIN_A3,0); //表示を消す delay_us(100); } if(digit== 1) //第2桁の表示 { output_b(LED_SEG[st[1]]); output_bit(PIN_A2,1); delay_ms (5); output_bit(PIN_A2,0); delay_us(100); } if(digit == 0) //第1桁の表示 { output_b(LED_SEG[st[0]]); output_bit(PIN_A1,1); delay_ms (5); output_bit(PIN_A1,0); delay_us(100); } digit ++; if(digit == 3) digit=0;//表示桁を変更 } }

  • PICのプログラムについて質問です

    使用するPICは16F84Aで、MPLAB IDEv8.88を使ってこのようなプログラムを作りました。 #include"pic.h" static void pic_init(); static void Delay_ms(unsigned char ms); static void Delay_1ms(); void main(){ pic_init(); while(1) { RB0 = 1 ; Delay_ms(250); Delay_ms(250); Delay_ms(250); RB0 = 0 ; Delay_ms(250); Delay_ms(250); Delay_ms(250); } static void pic_init() { // GPIO = 0b00000000; TRISA = 0xFF ; TRISB = 0x00 } static void Delay_ms(unsigned char ms) { unsigned char c; for (c=ms ; c>0 ; c--) { Delay_1ms(); } } static void Delay_1ms() { unsigned int cnt; unsigned int i; cnt = 76; for (i=0 ; i<cnt ; i++) { NOP(); } } ポートB0の出力を0から1にするプログラムなのですが、実行すると Error [314] C:\Users\moriwaki\Desktop\PIC program\step_test2.c; 52.24 ";" expected Error [254] C:\Users\moriwaki\Desktop\PIC program\step_test2.c; 77.0 undefined variable: "pic_init" ********** Build failed! ********** というエラーが出ます。このようなエラーが出る原因を教えて頂けないでしょうか。お願いします。

  • PICのSleepからの復帰に関して

    INTピンを使ってsleepから割り込み復帰したいのですが、 思ったとおり動いてくれません。 メインをSLEEPにし、割り込みが入ると割り込み側の プログラムを実行し、終わるとメインのSLEEPに もどってINTの割り込みに備えるようにしたいのです。 現段階では割り込みをするとSLEEPから割り込み には行くのですが、そのまま割り込み側のプログラムを 永遠に繰り返してしまいます。 list p=12f629 include p12f629.inc RELOOP1 equ 0x20 CT_DELAYNMS equ 0x21 PCLATH_TEMP equ 0x2a W_TEMP equ 0x2b STATUS_TEMP equ 0x2c stu equ 0x2d org 0x0 goto start org 0x4 ;レジスタの退避 movwf W_TEMP swapf STATUS,W clrf STATUS movwf STATUS_TEMP movf PCLATH,W movwf PCLATH_TEMP clrf PCLATH ;割り込み要因のチェック btfss INTCON, INTF goto INT_NEXT1 ;ここから割り込みプログラム 省略 INT_NEXT1 ;レジスタの復帰 movf PCLATH_TEMP,w movwf PCLATH swapf STATUS_TEMP,W movwf STATUS swapf W_TEMP,F swapf W_TEMP,W retfie ;初期設定 start: ;aLED単独の輝度 bcf STATUS, RP0 clrf INTCON clrf GPIO bsf STATUS, RP0 clrf OSCCAL clrf TRISIO bsf TRISIO,2 movlw B'01000101' movwf OPTION_REG bcf STATUS, RP0 ;割り込み許可する movlw B'11010000' movwf INTCON nop sleep nop goto $-3 end こんな感じのプログラムなのですが、INTピンからの割り込みと いうことでプリスケーラなどは使っていません。 データシートも読んだのですが今市理解ができていない状況です。 お願いします。

  • PIC16F88に書き込んだプログラムについて

    以前、直流電圧と電流を測定する回路を製作し、その時書いたプログラムでは正常にLCDに表示されていたのですが、最近になって測定した電圧および電流を1秒間に8回更新するように書き替えました。しかしLCDに正常に表示されなくなりました。 プログラムと回路図を掲載しますのでどなたか、どうすればいいか教えてください。 よろしくお願い致します。 ////////////////////以下プログラム/////////////////////////////////////////////////// <lcd.c> #include <pic.h> //#include "lcd.h" //#include "delay.h" #define _XTAL_FREQ 4000000 #define LCD_RS RA0 #define LCD_RW RA7 #define LCD_EN RA6 #define LCD_DATA PORTB #define LCD_STROBE() ((LCD_EN = 1),(LCD_EN=0)) /* write a byte to the LCD in 4 bit mode */ void lcd_write(unsigned char c) { //DelayUs(40); __delay_us(40); LCD_DATA = ( ( c >> 4 ) & 0x0F ); LCD_STROBE(); LCD_DATA = ( c & 0x0F ); LCD_STROBE(); } /* * Clear and home the LCD */ void lcd_clear(void) { LCD_RS = 0; lcd_write(0x1); //DelayMs(2); __delay_ms(2); } /* write a string of chars to the LCD */ void lcd_puts(const char * s) { LCD_RS = 1; // write characters while(*s) lcd_write(*s++); } /* write one character to the LCD */ void lcd_putch(char c) { LCD_RS = 1; // write characters lcd_write( c ); } /* * Go to the specified position */ void lcd_goto(unsigned char pos) { LCD_RS = 0; lcd_write(0x80+pos); } /* initialise the LCD - put into 4 bit mode */ void lcd_init() { char init_value; //ADCON1 = 0x06; // Disable analog pins on PORTA init_value = 0x3; //TRISA=0; //TRISB=0; LCD_RS = 0; LCD_EN = 0; LCD_RW = 0; //DelayMs(15); // wait 15mSec after power applied, __delay_ms(15); LCD_DATA = init_value; LCD_STROBE(); //DelayMs(5); __delay_ms(5); LCD_STROBE(); //DelayUs(200); __delay_us(200); LCD_STROBE(); //DelayUs(200); __delay_us(200); LCD_DATA = 2; // Four bit mode LCD_STROBE(); lcd_write(0x28); // Set interface length //lcd_write(0xF); // Display On, Cursor On, Cursor Blink lcd_write(0x0C); lcd_clear(); // Clear screen //lcd_write(0x6); // Set entry Mode lcd_write(0x07); } <main.c> #include <pic.h> #include <stdlib.h> #include "lcd.h" #define _LEGACY_HEADERS #define _XTAL_FREQ 4000000 __CONFIG(FOSC_INTOSCIO & WDTE_OFF & PWRTE_ON & MCLRE_OFF & BOREN_OFF & LVP_OFF & CPD_OFF & WRT_OFF & CCPMX_RB0 & CP_OFF); __CONFIG(FCMEN_OFF & IESO_OFF); unsigned int ADConv(unsigned char ch) { ADCON0=(ch<<3)&0x38; ADCS2=0; ADCS1=0; ADCS0=1; ADON=1; ADIF=0; __delay_us(20); GO_DONE=1; while(GO_DONE); return (ADRESH<<8) | ADRESL; } unsigned short Code2mV(unsigned char ch) { unsigned short ret; ret=0; ret += ADConv(ch)<<1; ret += ADConv(ch)>>1; ret += ADConv(ch)>>3; ret += ADConv(ch)>>4; ret += ADConv(ch)>>5; return ret; } void ioport(void) { CMCON=0x07; ANSEL= 0b00001110; TRISA = 0b00001110; PORTA=0x00; TRISB = 0b00000000; PORTB=0x00; } void main(void) { static double data, offset; static unsigned int v ,i,n1,n0; static unsigned char buf[8], cnt,tmp1[2],tmp2[2]; OSCCON = 0b01100000; // �N���b�N��8Mhz ioport(); ADCON1=0b11100000; lcd_init(); lcd_write(0x0D); lcd_goto(0); lcd_puts("Starting"); lcd_goto(0x40); lcd_puts("DC Meter"); __delay_ms(2500); lcd_clear(); offset=0.0; while (1) { data=0.0; for(cnt=0; cnt<10; cnt++) { data += Code2mV(1); } data /= 10.0; data *= 2.4287109375; data *= 11.0; data -= offset; v=(unsigned int)(data); n1=(unsigned int)(v/1000); n0=v-1000*n1; itoa(tmp2,n1,10); itoa(tmp1,n0,10); lcd_goto(1); lcd_puts(tmp2); lcd_goto(3); lcd_putch('.'); lcd_puts(tmp1); lcd_goto(6); lcd_puts("V"); data =0.0; for(cnt=0; cnt<10; cnt++) { data += Code2mV(2); } data /= 10.0; data *= 2.4287109375; data /= 11.0; offset = data; i=(unsigned int)(10.0 * data); itoa(buf,i,10); lcd_goto(9); lcd_puts(buf); lcd_goto(13); lcd_puts("mA"); __delay_ms(125); } }

  • PIC12F675、HC-SR04のプログラム

    PIC12F675にプログラムをMPLABX IPEで書き込んで、超音波センサ HC-SR04の距離が5cm以下の時にブザーが鳴る(出力が5Vになる)ようにしたいです。 以下のプログラムで出力は、距離に関わらず5Vか0Vで一定になっています。 プログラムに間違いがあれば、教えていただけないでしょうか。 #include <xc.h> #include <stdio.h> //12F675 #include <stdlib.h> #pragma config FOSC = INTRCIO // Oscillator Selection bits (INTOSC oscillator: I/O function on GP4/OSC2/CLKOUT pin, I/O function on GP5/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 // GP3/MCLR pin function select (GP3/MCLR pin function is digital I/O, MCLR internally tied to VDD) #pragma config BOREN = OFF // Brown-out Detect Enable bit (BOD disabled) #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) #define _XTAL_FREQ 32000000 #define TX_UART_SIZE 3 #define SONIC_TRIG GPIO5 #define SONIC_ECHO GPIO4 #define SONIC_TEMP GPIO2 #define SONIC_BUZZ GPIO1 #define IO_OFF 0 #define IO_ON 1 #define TIME_OFF -1 #define TIME_UP 0 #define TIME_START_H 0xD8 #define TIME_START_L 0xF0 #define TIME_LED_CNT_MAX 5 #define TIME_LED_CNT2_MAX 15 unsigned char cnt10ms; char TimerLed1; char TimerLed2; int main(int argc, char** argv) { long echo_time; long dist; OSCCAL = 0b00110000 ; // 内部クロック8MHz ANSEL = 0x00 ; // AN未使用、デジタルI/Oに割当てる CMCON = 0x07; // コンパレータ未使用 TRISIO = 0b00011100 ; // RA2,3,4を入力にし、他は出力に割当てる GPIO = 0b00000000 ; // 出力ピンの初期化(全てLOWにする) T1CON = 0b01110000 ; // ゲート有効、Hiでカウント、単一パルス、T1Gピン TMR1ON = 1; // タイマー1開始 while(1) { // タイマ1のカウンタ準備 TMR1 = 0; // カウンタの初期化TMR1 = 0; // トリガ送信 SONIC_TRIG = IO_ON; __delay_us( 10 ); SONIC_TRIG = IO_OFF; // エコー信号のON待ち while( SONIC_ECHO == IO_OFF ) { } // エコー信号のOFF待ち while( SONIC_ECHO == IO_ON ) { } // 超音波の往復時間を取得 echo_time = TMR1; // 往復時間から片道の時間にする echo_time /= 2; // パルス時間から距離(cm)に変更 dist = echo_time * 34 / 1000; if( dist <= 5 ) //距離5cm以下でブザー出力 { (SONIC_BUZZ = 1); } else { (SONIC_BUZZ = 0); } __delay_ms( 1000 ); } return (EXIT_SUCCESS); }

  • PICのプログラミングについて

    16F88をC言語でプログラムしています。 HI-TECH cでコンパイルしたところ、delay関数がうまく動作しません。 delay関数の直前までは動作するのですが、そこでストップしてしまいます。 どうもincludeの設定のところに問題があると思うのですが、 初心者なもので原因がいまひとつ掴めません。 とりあえず、delayが動作しているか確かめるために作った下記のプログラムでいろいろと試しているのですが、おかしいところがあればご指摘お願いします。 **************************** //RB0~RB4にはLEDを接続 #include <pic.h> #include <htc.h> #define _XTAL_FREQ 8000000 // 8Mhz __CONFIG(0x3F22); void main(){ TRISA = 0b00000100; TRISB = 0b00000000; PORTB = 0b00000101; __delay_ms(500); PORTB = 0b00000111; }

  • 分割ファイルのコンパイルができない

    こんにちは。 mikroCというコンパイラを使い、 以下の2つのファイルをコンパイル 使用と思っていますが、 「init12f683が宣言されていない」、という エラーが出てしまいます。 プログラム的に問題あるでしょうか( コンパイラでは、ひとつのプロジェクト を作成し、両方そこに加えてあります)。 ----init12f683.c(自作関数) void init12f683(){ GPIO=0; CMCON0=0b00000111; ANSEL=0b01110000; TRISIO=0b00010000; } ----picc1.c(main) extern void init12f683(void);*宣言はここと、 void main(){ extern void init12f683(void);*ここで両方試しました。 init12f683(); Delay_ms(1000); while(1){ GPIO.F0=1 ; Delay_ms(1000) ; GPIO.F0=0 ; Delay_ms(1000) ; } } externでの関数の宣言は、mainの外に置く場合と、 中に入れる場合、両方試しています。 問題が、プロジェクトファイルの設定にあるのか、 プログラム的におかしいのか(どこがおかしいのか)、 知りたいです。 何か分かる人がいましたら、 よろしくお願いします。

  • PIC16F84Aから16F628Aの変換について

    以前PIC16F84Aで問題なく動作しているプログラムを 初期設定を変えて(これでいいのか?も疑問)16F628Aで動かそうとしていますが サブルーチンに入り「タイマー」のルーチンから抜け出せないみたいです。 BILD ALL ではエラーは出ません。 割込みは正常に動作します。 どこがいけないのでしょうか? よろしくお願いいたします。 プログラムはこちらです。 ;------------------------------------------------------------------------- ;     初期設定 list P=pic16f628a include "p16f628a.inc" __CONFIG _HS_OSC & _CP_OFF & _WDT_OFF & _PWRTE_ON & _BODEN_ON & _LVP_OFF & _MCLRE_OFF ORG 0 GOTO MAIN ;----------------------------------------------------------------------- ; 割り込み処理 ORG 4     ;割り込みアドレス CLRW CLRF PORTB     ;ポートBクリア GOTO MAIN ;----------------------------------------------------------------------- ; メインプログラム MAIN   BCF STATUS,RP0          MOVLW B'00000111'         MOVWF CMCON         BSF INTCON,INTE     ;割りこみ許可?          BSF STATUS,RP0     ;ポートAを全て入力に設定         MOVWF TRISA          MOVLW H'01'     ;ポートBは0(ゼロ)以外は出力に設定         MOVWF TRISB         MOVLW 90H     ;INT割り込み許可         MOVWF INTCON         BCF STATUS,RP0     ;ポートBをクリア         CLRF PORTB          CLRW ;---------------------------------------------------------------------- ; スイッチ入力チエック LOOP    BTFSS PORTA,0     ;オープンSWがONか?          GOTO OPEN      ;ONだったら OPENへ         GOTO LOOP ;----------------------------------------------------------------------- ; オープン動作 OPEN    MOVLW 010H      ;ポートB4番に5V出力(リレーON)          MOVWF PORTB        MOVLW D'250'      ;動作時間 '250'設定         MOVWF 0EH      ;アドレス0EHに250を入力          CALL LOOP3      ;サブルーチンLOOP3を呼び出す        GOTO MAIN      ;サブルーチンが終わったら MAIN に戻れ ;------------------------------------------------------------------------ ;----------------------------------------------------------------------- ; サブルーチン(タイマー) TIMER1    MOVLW D'220'           MOVWF 0CH LOOP1    NOP           DECFSZ 0CH,1           GOTO LOOP1         RETURN TIMER2     MOVLW D'100'      ;アドレス0DHに100を入力          MOVWF 0DH LOOP2    NOP           CALL TIMER1      ;TIMER1を呼び出し(行く)           DECFSZ 0DH,1      ;アドレス0DH から1を引き算する           GOTO LOOP2      ;結果が"0"でなかったら LOOP2に戻ってまた引き算          RETURN       ;引き算の結果が"0"になったら「CALL」した「次に(下)」へ戻る LOOP3    NOP      ;何もしない          CALL TIMER2      ;TIMER2を呼び出す(行く)         DECFSZ 0EH,1         GOTO LOOP3          RETURN END    END

  • PIC12F675 ウォッチドッグタイマーの使い方

    最近趣味でPICアセンブラを初めた者です。 WDTの実験をするため以下のプログラムでリセットのかかるまでの時間を比べてみました。 私の考え違いかもしれませんが、WDTポストスケーラの値によってリセットするまでの時間は違うと思ったからです。 675のGP0~GP3の入力をOPTION_REG のbit0~bit3に割り当てました。 GP3はHに固定してあるのでOPTION_REG bit3(PSA)は常にHです。 プログラムは一秒間のLED点灯後消灯し、WDTリセットのかかるまでループします。 WDTリセットからのリスタートはLEDを点滅後、同じことを繰り返します。 このときGP0~GP2の端子を切り替えることにより、OPTION_REGのWDT分周比を変え、 LED消灯後、リスタートし、点滅するまでの時間が変わると思ったのですが、変化しません。 正確な時間はわかりませんが、GP0~GP2を変えても、リスタートまでの時間は三秒程度一定です。 OPTION_REGのbit0~bit2がすべて立ってるのではと思われるのですが、 私のWDTの設定に対する考え方が間違ってるのか、テスト用のプログラムにミスがあるのかわかりません。 お暇な時で結構ですので、お教えくださるよう、どうぞよろしくお願いいたします。 title WDT list p=12f675 #include <p12f675.inc> errorlevel -302 __CONFIG _CP_OFF & _CPD_OFF & _BODEN_OFF & _MCLRE_OFF & _WDT_ON & _PWRTE_ON & _INTRC_OSC_NOCLKOUT org 20h work RES 1 ; ワーク counter RES 1 ; 回数カウンター cnt10m RES 1 ; 10ms時間稼ぎ用ワーク cnt500u RES 1 org 0 goto start start bsf STATUS, RP0 ; レジスタバンク1を選択 call h'3ff' movwf OSCCAL ; 書き込む movlw b'00001111' ; GP0~GP3を入力設定 movwf TRISIO clrf ANSEL ; すべてデジタルI/O bcf OPTION_REG, NOT_GPPU ; プルアップ使用する bcf STATUS,RP0 ; バンクゼロ btfsc STATUS,NOT_TO goto start2 movlw d'5' ; LED 点滅回数を5回にして call led_on_off start2 bsf GPIO,GP5 ; 一秒間LEDを点灯し call tm1000 movf GPIO,w ; 入出力ピンを読んで b3は一番ピンに直結し常時 H andlw b'00001111' ; 下位4ビットだけ選び bsf STATUS,RP0 ; バンク 1 選択 iorwf OPTION_REG,f ; ウォッチドッグの分周比とする bcf STATUS,RP0 ; バンク 0 loop bcf GPIO,GP5 ; LED消灯し goto loop ; リセットがかかるまでループ ; LED を0.1秒ごとにWレジスタの回数点滅 led_on_off movwf work led_loop decfsz work goto led_loop2 return led_loop2 bsf GPIO,GP5 call tm100 bcf GPIO,GP5 call tm100 goto led_loop ;-------------- 1000ms,100ms 遅延ルーチン tm1000 movlw D'100' goto lp200 tm500 movlw D'50' goto lp200 tm100 movlw D'10' ;10ms遅延を10回で100ms lp200 movwf counter ;カウンターをセットし lp201 decfsz counter,f ;カウンターはゼロ ? goto lp202 ;いいや return lp202 call t10m goto lp201 ; 10msec 遅延ルーチン for 4Mz t10m movlw d'8' movwf cnt10m tm10lp1 movlw d'249' movwf cnt500u tm10lp2 clrwdt ; ウォッチドッグタイマーをクリア nop decfsz cnt500u,f goto tm10lp2 decfsz cnt10m,f goto tm10lp1 return END