UMEHOSHI ITA TOP PAGE COMPUTER SHIEN LAB
このページは、UMEHOSHI ITA のCN6とCN7のPWD制御の一部をROM化して、
しかもRAM領域に「UME専用Hexコマンド」文字列を送信することで、プログラム送信や実行もでききる状態を維持する変更を
紹介しています。
まず、以前に紹介したPWM操作用のハードのリンクがここにあり、
ここで示したハードを制御するROM化が目標です。
また、このページで紹介した[UMEHOSHI ITA]のプログラムを利用しています。
この制御で必要な[UMEHOSHI ITA]のAPIは、このリンクの呼び出しを使っています
#include <xc.h> // app_pwm_esp32.c #include "common.h" #define BASE_FUNC 0x9D020000 // EEPROM領域配置用 //#define BASE_FUNC 0x80005000 // RAM領域配置用 #define AdrStart BASE_FUNC // アプリの起動時の初期ルーチンのアドレス #define AdrForward (BASE_FUNC+0x0200) // モータ前進ルーチンのアドレス #define AdrGoBack (BASE_FUNC+0x0300) // モータ後進ルーチンのアドレス #define AdrRight (BASE_FUNC+0x0400) // モータ右回転ルーチンのアドレス #define AdrLeft (BASE_FUNC+0x0500) // モータ左回転ルーチンのアドレス #define AdrUpLeft (BASE_FUNC+0x0600) // モータ左デューティ幅アップ #define AdrDownLeft (BASE_FUNC+0x0700) // モータ左デューティ幅ダウン #define AdrUpRight (BASE_FUNC+0x0800) // モータ右デューティ幅アップ #define AdrDownRight (BASE_FUNC+0x0900) // モータ右デューティ幅ダウン #define AdrStop (BASE_FUNC+0x0A00) // モータ停止 #define AdrTimer2 (BASE_FUNC+0x0B00) // 指定時間後にモータ停止のTimer2用アドレス #define AdrBeep (BASE_FUNC+0x0D00) // ビープ音 #define AdrSetCN6 (BASE_FUNC+0x0E00) // CN6(左側) コネクタの制御 #define AdrSetCN7 (BASE_FUNC+0x0F00) // CN7(右側) コネクタの制御 #define UPDAOWN 0x1000 // デューティ幅の変更で使う値(この値を加算又は減算) typedef struct { int cn6PWM; // 現在の左デューティ幅で、初期設定 int cn7PWM; // 現在の右デューティ幅で、初期設定 int time2Count;//Timer2割り込みでカウントアップ(下記stopCountまでカウント) int stopCount; // time2CountがstopCount以上で、time2CountがをゼロにしてモータをOFF } MortorCtrl; #define MT ((MortorCtrl *)0xA0009000) // ram_area3領域の絶対アドレスで、グローバル変数を定義 __attribute__((address( AdrStart ))) void start (void); void start() { // 左右のモータで、進行にバラツキがある場合、下記初期設定を調整して合わせる。 MT->cn6PWM = 0x04FFF; // 現在の左デューティ幅で、初期設定 MT->cn7PWM = 0x04FFF; // 現在の右デューティ幅で、初期設定 MT->time2Count = 0;//Timer2割り込みでカウントアップ(下記stopCountまでカウント) MT->stopCount = 0x500;// time2CountがstopCount以上で、time2CountがをゼロにしてモータをOFF PORTBCLR = 0b0110000000001100;//モータ関連ポート(14,13,3,2)をゼロにする IEC0CLR = 0x00000200;//T2IE Timer2 Enable(割込み不可)"); // 初期化ルーチン(リセット時の処理)を設定 ( (uint32_t *)_HANDLES)[_IDX_INIT_SUB_FUNC] = (uint32_t ) AdrStart; __asm__ ("NOP"); // Timer2の割り込み処理を置き換える ( (uint32_t *)_HANDLES)[_IDX_TIMER_2_FUNC] = (uint32_t ) AdrTimer2; PR2=0x09c3F; // Timer2の周期設定 _set_pwd_mode(1); // PWM モードへ変更 T2CONbits.ON = 1; //Timer2の機能を有効 MT->time2Count =0; _RB15 = 0; // LED D1を消灯 _clear_beep_code(); _set_beep_code((uint8_t)0b00100011);//音パターン[・・−]の登録 _UM_PTR_GOTO_BEEP = NULL;//ループ生成OFF } // モータを停止する。(割り込み不可も行う) __attribute__((address( AdrStop))) void stop(void); void stop() { IEC0CLR = 0x00000200;//T2IE Timer2 Enable(割込み不可)"); OC5RS = OC1RS = OC4RS = OC3RS = 0;// モータすべてをOFF MT->time2Count = 0; } // タイマーで(stopCount 値に達するまで)の時間ごとに、モータを停止する。 // モータがオンで、移動し続けないようにする考慮で、stop内で割り込みを不可にしている。 __attribute__((address( AdrTimer2))) void timer2(void); void timer2() { IFS0CLR = 0x00000200; // Clear the timer interrupt status flag if( ++MT->time2Count >= MT->stopCount ){ stop();// PWM パルス幅を0 _RB15 = 0; // LED1消灯 } } // CN6(左側) コネクタの制御 dの値 0停止, 1:正転, -1:逆転 __attribute__((address( AdrSetCN6 ))) void setCN6(int); void setCN6( int d){ OC5RS = 0x0; // CN6[1-2]制御(RB2) OC1RS = 0x0; // CN6[3-4]制御(RB3) if(d==1){ OC5RS = MT->cn6PWM; // CN6[1-2]制御(RB2) OC1RS = 0x0; // CN6[3-4]制御(RB3) } else if(d==-1){ OC5RS = 0x0; // CN6[1-2]制御(RB2) OC1RS = MT->cn6PWM; // CN6[3-4]制御(RB3) } } // CN7(右側) コネクタの制御 dの値 0停止, 1:正転, -1:逆転 __attribute__((address( AdrSetCN7 ))) void setCN7(int); void setCN7( int d){ OC4RS = 0x0; // CN7[3-4]制御(RB13) OC3RS = 0x0; // CN7[1-2]制御(RB14) if(d==1){ OC4RS = MT->cn7PWM; // CN7[3-4]制御(RB13) OC3RS = 0x0; // CN7[1-2]制御(RB14) } else if(d==-1){ OC4RS = 0x0; // CN7[3-4]制御(RB13) OC3RS = MT->cn7PWM; // CN7[1-2]制御(RB14) } } __attribute__((address( AdrBeep ))) void beep (void); void beep() { _clear_beep_code(); _set_beep_code((uint8_t)0b111100100);//音パターン[−−−−]の登録 _UM_PTR_GOTO_BEEP = NULL;//ループ生成OFF } // モータ前進ルーチン __attribute__((address( AdrForward ))) void forward(void); void forward() { MT->time2Count = 0; MT->stopCount = 300; setCN6( 1 );// 左正転 setCN7( 1 );// 右正転 _RB15 = ! _RB15;//確認用のLED1点灯反転 IEC0SET = 0x00000200;//T2IE Timer2 Enable(割込み許可)"); } // モータ後進ルーチン __attribute__((address( AdrGoBack ))) void goback(void); void goback() { MT->time2Count = 0; MT->stopCount = 200; setCN6( -1 );// 左逆転 setCN7( -1 );// 右逆転 _RB15 = ! _RB15;//確認用のLED1点灯反転 IEC0SET = 0x00000200;//T2IE Timer2 Enable(割込み許可)"); } // モータ右回転ルーチン __attribute__((address( AdrRight ))) void right(void); void right() { MT->time2Count = 0; MT->stopCount = 100; setCN6( 1 );// 左正転 setCN7( -1 );// 右逆転 _RB15 = ! _RB15;//確認用のLED1点灯反転 IEC0SET = 0x00000200;//T2IE Timer2 Enable(割込み許可)"); } // モータ左回転ルーチン __attribute__((address( AdrLeft ))) void left(void); void left() { MT->time2Count = 0; MT->stopCount = 100; setCN6( -1 );// 左逆転 setCN7( 1 );// 右正転 _RB15 = ! _RB15;//確認用のLED1点灯反転 IEC0SET = 0x00000200;//T2IE Timer2 Enable(割込み許可)"); } // モータ左デューティ幅アップルーチン __attribute__((address( AdrUpLeft ))) void upleft(void); void upleft() { //_send_hex_low( cn6PWM ); if( MT->cn6PWM +UPDAOWN <= 0x0ffff){ MT->cn6PWM += UPDAOWN ; //_send_string(" Left UP\r\n"); } else { beep(); //_send_string(" Left FULL\r\n"); } _RB15 = ! _RB15;//確認用のLED1点灯反転 } // モータ左デューティ幅ダウンルーチン __attribute__((address( AdrDownLeft ))) void downleft(void); void downleft() { //_send_hex_low( MT->cn6PWM ); if( MT->cn6PWM - UPDAOWN >= 0){ MT->cn6PWM -= UPDAOWN ; //_send_string(" Left DOWN\r\n"); } else { beep(); //_send_string(" Left Minimum\r\n"); } _RB15 = ! _RB15;//確認用のLED1点灯反転 } //モータ右デューティ幅アップ __attribute__((address( AdrUpRight ))) void upright(void); void upright() { //_send_hex_low( MT->cn7PWM ); if( MT->cn7PWM +UPDAOWN <= 0x0ffff){ MT->cn7PWM += UPDAOWN ; //_send_string(" Right UP\r\n"); } else { beep(); //_send_string(" Right FULL\r\n"); } _RB15 = ! _RB15;//確認用のLED1点灯反転 } // モータ右デューティ幅ダウン __attribute__((address( AdrDownRight ))) void downright(void); void downright() { //_send_hex_low( MT->cn7PWM ); if( MT->cn7PWM -UPDAOWN >= 0){ MT->cn7PWM -= UPDAOWN ; //_send_string(" Right DOWN\r\n"); } else { beep(); //_send_string("Right Minimum\r\n"); } _RB15 = ! _RB15;//確認用のLED1点灯反転 }以上のコードをumehoshiEditの開発ツールで作成し、 転送するだけで、EEPROM領域(0x9D020000)に書き込まれます。
#include <xc.h>
#include "common.h"
#define StartInit ((void (*)(void) )0x9D020000)// タイマー割り込み初期設定
#define Forward ((void (*)(void) )0x9D020200)// モータ前進ルーチンのアドレス
#define GoBack ((void (*)(void) )0x9D020300)// モータ後進ルーチンのアドレス
#define Right ((void (*)(void) )0x9D020400)// モータ右回転ルーチンのアドレス
#define Left ((void (*)(void) )0x9D020500)// モータ左回転ルーチンのアドレス
#define Stop ((void (*)(void) )0x9D020A00)// モータ停止
#define Timer2 ((void (*)(void) )0x9D020B00)// タイマー2割り込み
#define Beep ((void (*)(void) )0x9D020D00)// 所定パターンのビープ音起動
typedef struct {
int cn6PWM; // 現在の左デューティ幅で、初期設定
int cn7PWM; // 現在の右デューティ幅で、初期設定
int time2Count;//Timer2割り込みでカウントアップ(下記stopCountまでカウント)
int stopCount; // time2CountがstopCount以上で、time2CountがをゼロにしてモータをOFF
} MortorCtrl;
#define MT ((MortorCtrl *)0xA0009000) // ram_area3領域の絶対アドレスで、グローバル変数を定義
void WaitBeep() //音出して、1秒待つ
{
Beep();//音パターン[−−−−]の登録、ループ無し
MT->time2Count = 1000;
IEC0SET = 0x00000200;//T2IE Timer2 Enable(割込み許可)
}
void timer2_interrupt()// 割り込み関数
{
static int step=0;
static void (*funcs[])(void)={ // 実行する順番で関数を登録(各関数内で、Timer2割り込みをイネーブルにする必要がある)
WaitBeep, // 音を出して一時停止
Forward, // 前進関数
Right, // 右回転関数
WaitBeep, // 音を出して一時停止
Left, // 左回転関数
GoBack, // 後進関数
};
Timer2(); // 内部でMT->time2Count++を行って、MT->stopCount以上なら0になり、Timer2割り込みがディセーブルになる。
if( MT->time2Count != 0) return; // time2Countまだ動作中
if( step >= 6 ) step = 0;
funcs[step++]();// 上記で配列に登録した関数を、順番に実行する。
}
// RAM領域の起動アドレス
__attribute__((address( 0x80005000 ))) void start (void);
void start()
{
//Beep();
StartInit();// Timer2のON、割り込み処理デフォルト関数登録、割り込み不可
( (uint32_t *)_HANDLES)[_IDX_TIMER_2_FUNC] = (uint32_t ) timer2_interrupt;// Timer2の割り込み処理を置き換える
__asm__ ("NOP");
MT->stopCount = 3000;// 最初の割り込み内のstop()タイミング (3秒後)
IEC0SET = 0x00000200;//T2IE Timer2 Enable(割込み許可)
}
なお、USBケーブルを接続したままで実行すると雑音で誤動作しがちなので、実行スタートを3秒に設定しています。Beep R009D020D00003B
StartInit R009D020000004F関数の中からも呼び出しており、これでモータを停止し、TIMER2の割り込みを不可にしている。
Timer2 R009D020A00003E
Forward R009D020200004D
Back R009D020300004C
Right R009D020400004B
Left R009D020500004A