/****************************/ /* PWM出力のテスト */ /****************************/ // USB(Serial)で通信 // Serial1でPWM値の変化を出力 // PWM周波数は500Hz, 8bit分解能 // タイトル const char ttl_msg[] = "# Pico PWM Test #5 (2023-02-22)"; const char *inp_msg[] = { // inp_modeで区分して出力 "# PWM Port >", // 0:PWMポート番号入力 "# PWM Freq (500Hz) >", // 1:PWM 周波数 "# PWM Range (256) >", // 2:PWM レンジ "# PWM Data >", // 3:PWM データ入力 }; // LED点滅 #define LED_PORT 25 // 1出力でLEDオン /****************************/ /* 送受データ */ /****************************/ /***** 送信データ *****/ char tx_str[64]; // 送信文字列 /***** シリアル1行入力 *****/ #define RXBF_SIZ 32 // 文字バッファ文字数 char rx_bff[RXBF_SIZ+1]; // 受信文字バッファ (+null) byte f_rxok; // 受信データありフラグ /***** シリアル1行受信 *****/ // CRでターミネート f_rxokを1に // エコーバックありで // なし→BSで1文字戻す void rxbff(void) { static byte cnt = 0; // 受信文字数 char c; if(Serial.available()){ // 受信データあり if(f_rxok == 0){ // 前データ受信処理した c = Serial.read(); // 1文字読み出し if(c == '\r'){ // CR? rx_bff[cnt] = '\0'; // nullを最後に Serial.println(); // 改行 f_rxok = 1; // 受信成功 cnt = 0; // 最初から } else if(c == '\x08'){ // BS? if(cnt > 0){ cnt--; // 1文字戻す Serial.print("\b \b"); // BS,space,BS } } else{ // 文字 if((cnt < RXBF_SIZ) && // バッファサイズ内 (isprint(c))){ // 表示可能文字0x20~0x7E Serial.write(c); // エコーバック rx_bff[cnt] = c; // バッファに入れる cnt++; // 1文字進める } } } } } /****************************/ /* PWM出力 */ /****************************/ #include "pwm.h" // PWM処理に必要 // PWMデータ int pwm_port; // PWMポート番号 int pwm_freq = 500; // PWM 周波数 初期値は500Hz int pwm_range = 256; // PWM レンジ 初期値は256 int pwm_data; // PWM設定値データ int pwm_mlt; // valへの乗数 pwmStartのリターン値 // チェックデータ float pwm_ckdiv; // ckdiv値 /***** PWM出力 *****/ // pinに出力 valがPWM H区間 最大がrange(分解能) // val=0ならL出力 val=rangeならH出力 // ピコのクロックは125MHz // val,rangeを10倍して処理 // set_clkdivは256.0未満 m・n/16で分周 // set_wrap,set_chan_levelはuint16_tなので65535がmax // frq:Hz単位のPWM周波数 // val値の乗数を持ってリターン // 以後はval値にmltを乗じてpwmVal(pin, val, mlt)でPWMを発生できる int pwmStart(pin_size_t pin, int val, int range, int frq) { uint sn; // slice number(0~7) float ckdiv; // clkdiv値 256.0未満 int mlt; // val値の乗数 gpio_set_function(pin, GPIO_FUNC_PWM); // ポートをPWM出力に mlt = 1; // 乗数=1から while(1){ // 125MHzからckdiv値を計算 ckdiv = 125.0e6 / (float)(mlt * frq * range); if(ckdiv < 256.0) break; // 256未満ならok mlt++; // 乗数を1増やす } sn = (pin / 2) & 7; // スライス番号はpin番号の1/2で0~7の8コ pwm_set_clkdiv(sn, ckdiv); // 125MHz / ckdiv pwm_set_wrap(sn, (mlt * range) - 1); // PWM 分解能 pwm_set_chan_level(sn, pin & 1, mlt * val); // ch-A,ch-B pwm_set_enabled(sn, true); // PWMスタート pwm_ckdiv = ckdiv; // ckdiv値 return mlt; } /***** PWM値セット *****/ // valはmltを乗じた値 void pwmVal(pin_size_t pin, int val, int mlt) { pwm_set_chan_level((pin / 2) & 7, // slice number 0~7 pin & 1, // ch-A,ch-B mlt * val); // 16bit PWMデータ } /*********************************/ /* 制御実行処理 */ /*********************************/ // 制御用データ int inp_mode; // 入力モード // 0 : PWMポート番号 // 1 : PWM 周波数 freq // 2 : PWM 分解能 range // 3 : PWM データ data int tm_100ms; // 100ms ダウンカウントタイマー /***** 制御実行区分 *****/ byte j_exc; // 実行区分 #define J_DATAIN 1 // データ入力 #define J_SCAN 3 // PWMスキャン /***** スタンバイ *****/ // 最初のCR入力を待ってタイトル表示 void jstby(void) { if(f_rxok){ // CR入力待ち f_rxok = 0; Serial.println(); // 改行 Serial.println(ttl_msg); // タイトル出力 j_exc++; // next exc } } /***** 数値入力 入力項目表示 *****/ // inp_modeで入力対象を変更 void jdatain(void) { Serial.print(inp_msg[inp_mode]); // 入力項目 j_exc++; // next exc } /***** 数値入力 データ入力処理 *****/ // PWMポート番号あるいはPWMデータ void jdatain1(void) { int d; int n; if(f_rxok){ // CR入力待ち f_rxok = 0; n = strlen(rx_bff); // 文字数 d = atoi(rx_bff); // 数値に変換 switch(inp_mode){ case 0: // PWM port : ポート番号入力 if(n){ // 入力文字あり pwm_port = d; // ポート番号を設定 inp_mode++; // 次はレンジ } j_exc = J_DATAIN; break; case 1: // PWM frwq : 周波数を入力 if(n){ // 入力文字あり pwm_freq = d; // 周波数を設定 } // 入力なくても inp_mode++; // range入力に j_exc = J_DATAIN; break; case 2: // PWM range : 分解能を入力 if(n){ // 入力文字あり pwm_range = d; // 分解能を設定 } // 入力なくても pwm_mlt = pwmStart(pwm_port, // ポート番号 pwm_range/2, // PWM duty 50%出力 pwm_range, // 分解能 pwm_freq); // 周波数 sprintf(tx_str, "PWM:%d m:%d 1/%4.3f", pwm_port, pwm_mlt, pwm_ckdiv); Serial.println(tx_str); inp_mode++; // データ入力に j_exc = J_DATAIN; break; case 3: // PWMデータ入力 if(n == 0){ // 入力文字なし inp_mode = 0; // PWMポート入力に j_exc = J_DATAIN; // 戻してもう一度 } else{ // 入力あり pwm_data = d; if(pwm_data >= 0){ // 0~プラスならPWM値セット pwmVal(pwm_port, pwm_data, pwm_mlt); // PWM出力 sprintf(tx_str, "%d/%d %4.3f%%", pwm_data, pwm_range, 100.0 * ((float)pwm_data / (float)pwm_range)); Serial.println(tx_str); j_exc = J_DATAIN; // 繰り返し } else{ // マイナスなら連続可変へ Serial.println("Scan."); pwm_data = 1; // 1~pwm_range-1まで j_exc = J_SCAN; // 出力開始 } } break; } } } /***** PWM値連続可変 *****/ // 2秒サイクルで出力 void jscan(void) { pwmVal(pwm_port, pwm_data, pwm_mlt); // PWM出力 sprintf(tx_str, "%4d", pwm_data); Serial.println(tx_str); // USB Serial1.println(tx_str); // TX1 tm_100ms = 20; // 2秒タイマーセット j_exc++; // next exc } /***** PWM値連続可変 #1 *****/ // タイムアップで次データへ void jscan1(void) { byte bk = 0; if(f_rxok){ // CR入力で中断 f_rxok = 0; Serial.println("Break."); bk = 1; } if(tm_100ms == 0){ // タイムアップした pwm_data++; // PWM値を+1 if(pwm_data >= pwm_range){ // 1~255を出力完了? Serial.println("Finish."); bk = 1; // おわり } else{ // 時間待ち j_exc = J_SCAN; // PWM出力続行 } } if(bk){ // おわり inp_mode = 0; // PWMポート番号入力に j_exc = J_DATAIN; // 戻してもう一度 } } /********************************/ /* 制御実行テーブル */ /********************************/ /***** 制御実行 *****/ void (*jexc[])(void)={ jstby, // 0:スタンバイ jdatain, // * 1:データ入力 jdatain1, // 2 jscan, // * 3:連続PWM出力 jscan1, // 4 }; /****************************/ /* SETUP */ /****************************/ /***** SETUP *****/ void setup() { Serial.begin(9600); // USB TX,RX Serial1.begin(9600); // TX1 Serial1.println(); // 改行だけ pinMode(LED_PORT, OUTPUT); // LED } /****************************/ /* LOOP */ /****************************/ /***** LOOP *****/ void loop() { byte f_led = 0; // LED点滅用 uint32_t t0, t1; // タイマー t0 = millis(); while(1){ t1 = millis(); if((t1 - t0) >= 100){ // 0.1秒経過? t0 = t1; f_led ^= 1; // LED トグル gpio_put(LED_PORT, f_led); // LED出力 if(tm_100ms) tm_100ms--; // 100ms ダウンカウントタイマー } rxbff(); // 1行受信処理 jexc[j_exc](); // 制御実行区分で } } /*==== end of "pwm_serial_in5.ino" ====*/