Skip to content

Instantly share code, notes, and snippets.

@7m4mon
Last active February 28, 2018 14:46
Show Gist options
  • Save 7m4mon/0d2a13921ad0424b8396bea14056959f to your computer and use it in GitHub Desktop.
Save 7m4mon/0d2a13921ad0424b8396bea14056959f to your computer and use it in GitHub Desktop.
/*
* ふみきりのオモチャ
* 2018/02/28 7M4MON
* Memory usage: ROM=19% RAM=16% - 19%
*/
#include <12f683.h> // サーボを使うのでCCPモジュールがある683を選定
#fuses INTRC_IO, NOWDT, PUT, NOPROTECT, NOMCLR, NOBROWNOUT
#use Delay(CLOCK=4000000) // 1cycle = 1us
#use fast_io(a)
#define PIN_LED1 PIN_A0
#define PIN_LED2 PIN_A1
#define PIN_SERVO PIN_A2
#define PIN_EXE PIN_A3
#define PIN_CANCEL PIN_A4
#define PIN_BUZZ PIN_A5
/* タイマの定数は実機での実験結果により10% 早めた値にする */
#define BUZZ_TIME_523 (239) // 523Hz -> 1912us周期、半周期は 938us、タイマの都合で8bit,DIV_4 → 938 ÷ 4 (タイマ2は減算カウンタ)
#define BUZZ_TIME_659 (190) // 659Hz -> 1517us周期、半周期は 759us、タイマの都合で8bit,DIV_4 → 759 ÷ 4 (タイマ2は減算カウンタ)
#define INTRPT_50MS (255 - 160) /* 約50ms毎*/
#define POST_500MS_DIV 5 /* 250ms ÷ 50ms */
#define EXE_TIMEOUT (20*4) /* 20秒 */
#define SERVO_CYCLE (65535-20000) // 20ms → サーボモーターのサイクル
#define SERVO_H_DEG (SERVO_CYCLE + 1100) // 1ms = 0°
#define SERVO_V_DEG (SERVO_CYCLE + 2000) // 2ms = 90°
#define SERVO_POS_DIV 5 // サーボの動かすポジションの分割数
#define SERVO_MOVE_DEG ((SERVO_V_DEG - SERVO_H_DEG) / SERVO_POS_DIV)
#define SERVO_MOVE_ADD 1 // サーボモーターを角度が一致してから何回動作させるか
/* グローバル変数 */
unsigned int1 exe = 0; /* 実行中フラグ */
unsigned int8 exe_time = 0; /* 0:L点灯_BUZZ_OFF, 1:0:L点灯_BUZZ_ON, 2:R点灯_BUZZ_OFF, 3:R点灯_BUZZ_ON */
unsigned int8 postscale = POST_500MS_DIV;
unsigned int8 buzz_state = 0;
signed int8 servo_move = 0;
unsigned int16 deg = SERVO_V_DEG;
/* TIMER1はサーボモーター制御のため、コンペアモードで使う*/
// 20ms毎にパルスを出力する。
#INT_TIMER1
void timer1_isr(){
set_timer1(SERVO_CYCLE);
if(servo_move > 0){
output_high(PIN_SERVO);
}
}
#INT_CCP1 //コンペアマッチ割り込み
void ccp1_isr(){ //出力をLowにする
output_low(PIN_SERVO);
}
/* カンカン音の周期での割り込み */
#INT_TIMER2
void set_buzzer(void){
unsigned int8 buzz_time;
if(exe && (exe_time & 1) ){ /* 実行中かつexe_timeが奇数だったら */
output_toggle(PIN_BUZZ);
buzz_state++;
buzz_state &= 3; // 4→0
/* 523Hzと659Hzを交互に鳴らす*/
buzz_time = (buzz_state & 2) ? BUZZ_TIME_523 : BUZZ_TIME_659;
set_timer2(buzz_time);
}else{
output_low(PIN_BUZZ);
}
}
/* サーボモーターの角度を決める。実行中なら角度上げ、停止中なら角度下げ */
void set_servo(void){
unsigned int16 deg_work;
signed int8 servo_move_work;
deg_work = exe ? (deg - SERVO_MOVE_DEG) : (deg + SERVO_MOVE_DEG);
if((deg_work > SERVO_V_DEG)){
deg_work = SERVO_V_DEG;
}else if(deg_work < SERVO_H_DEG){
deg_work = SERVO_H_DEG;
}
/* 角度が一致して動かす必要がない場合は止める */
servo_move_work = (deg == deg_work) ? (servo_move - 1) : SERVO_MOVE_ADD;
servo_move = (servo_move_work < 0) ? 0 : servo_move_work;
CCP_1 = deg_work;
deg = deg_work;
}
/* ブザー用の割り込み許可(サーボと排他利用) */
void enable_interrupt_buzz(void){
disable_interrupts(INT_TIMER1); //タイマ1(サーボ)割込み禁止
disable_interrupts(INT_CCP1); //CCP(サーボ)割り込み禁止
set_timer2(BUZZ_TIME_523);
enable_interrupts(INT_TIMER2); //タイマ2(ブザー)割込み許可
enable_interrupts(INT_TIMER0); //タイマ0割込み許可
}
/* サーボ用の割り込み許可(ブザーと排他利用) */
void enable_interrupt_servo(void){
disable_interrupts(INT_TIMER2); //タイマ2(ブザー)割込み禁止
set_servo();
set_timer1(SERVO_CYCLE);
enable_interrupts(INT_TIMER1); //タイマ1(サーボ)割込み許可
enable_interrupts(INT_CCP1); //CCP(サーボ)割り込み許可
enable_interrupts(INT_TIMER0); //タイマ0割込み許可
}
/* 50msに一度のタイマ割り込み */
#INT_RTCC
void set_cross_state(void){
disable_interrupts(GLOBAL); //グローバル割込み禁止
if(postscale == 0){ /* 250ms */
postscale = POST_500MS_DIV;
if(exe){
exe_time++;
exe = (exe_time > EXE_TIMEOUT) ? 0 : 1;
if(exe_time & 2){
output_low(PIN_LED2);
output_high(PIN_LED1);
}else{
output_low(PIN_LED1);
output_high(PIN_LED2);
}
if(exe_time & 1){
enable_interrupt_buzz();
}else{
enable_interrupt_servo();
}
}else{ // 停止中
output_low(PIN_LED1);
output_low(PIN_LED2);
exe_time = 0;
enable_interrupt_servo();
}
}else{
postscale--;
}
set_timer0(INTRPT_50MS);
enable_interrupts(GLOBAL); //グローバル割込み許可
}
/* ボタンをチェックして動作状態を決定する。 */
void check_button(void){
/* 三項演算子だとうまく動かないのでベタに書くことにする。 */
//exe = input(PIN_EXE) ? exe : 1; // 実行ボタンが押されたら実行にする
//exe = input(PIN_CANCEL) ? exe : 0; // 停止ボタンが押されたら停止にする
if(!input(PIN_EXE)){
exe = 1;
}else if (!input(PIN_CANCEL)){
exe = 0;
}
}
void main(void){
/*ピンの設定*/
setup_adc_ports(NO_ANALOGS);
port_a_pullups(0b00010000);
set_tris_a(0b00011000); // 3,4が入力
/* 割り込み設定 */
setup_counters(RTCC_INTERNAL , RTCC_DIV_256); // 256us毎
set_timer0(INTRPT_50MS); // 50ms毎
setup_timer_2(T2_DIV_BY_4,BUZZ_TIME_523,1); // 4us毎
set_timer2(BUZZ_TIME_523);
//CCPの設定
CCP_1 = SERVO_H_DEG; //初期化
setup_ccp1(CCP_COMPARE_INT); //CCP1コンペアマッチした時の動作
setup_timer_1(T1_INTERNAL | T1_DIV_BY_1); //内部クロック使用 プリスケーラ1倍
set_timer1(SERVO_CYCLE);
enable_interrupts(INT_TIMER0); //タイマ0割込み許可
disable_interrupts(INT_TIMER1); //タイマ1割込み許可
disable_interrupts(INT_TIMER2); //タイマ2割込み許可
disable_interrupts(INT_CCP1); //CCP割り込み許可
enable_interrupts(GLOBAL); //グローバル割込み許可
while(true){
check_button(); /* ボタンの状態をチェック */
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment