Hobby Lab 趣味のモノ作り実験のサイトです。
部品 プロセッサー他 CH32V 203_test_GPIO
 0 プログラムの手順
 1 クロック速度の設定
 1.1 クロック速度とは
 1.2 設定方法
 2 I/Oの設定
 2.1 設定の概要
 2.2 記述方法
 3 信号出力プログラム
 3.1 プログラムの概要
 3.2 記述方法
 4 信号入力プログラム
 4.1 プログラムの概要
 4.2 記述方法
 5 割り込みプログラム
 5.1 割り込みの必要性
 5.2 割り込み無しのプログラム
5.2.1 要望する動作
5.2.2 プログラム
5.2.3 プログラムの実行波形
5.2.4 プログラムの問題点
 5.3 割り込みを使うプログラム
5.3.1 プログラム概要
5.3.2 プログラムの流れ
5.3.3 プログラム
5.3.4 割り込みプログラム説明
5.3.5 割り込み優先順位説明

Pr:Prプロセッサ関係
PrP:プロセッサ
動作比較
 STM32F動作比較
 CH32V203&STM32F 動作比較
 arduino動作比較
raspberrypi関係
 RaspberryPiハード
CH32V関係
 -CH32V開始
 -203K8T6(32Pin)開始
 -203C8T6(48P)開始
 -003J4M6(8Pin)開始
 -003F4P6(20Pin)開始
 -Moun River StudioⅡ
 プログラミング!
  203_GPIO関係
  203_TIME関係
  203_TIME Encoder
  203_I2C関係
  203_1-Wire関係
  003_DS18B20テスター
  USART(UART)関係
  DS18B20をModBus制御
 -マニュアル
 203データシート
 203取説
  MBA メモリとバス方式
  PWR 電力制御
  RCC リセット・拡張・クロック
  BKP バックアップレジスタ
  CRC 巡回冗長検査
  RTC リアルタイムクロック
  GPIO GPIOと代替機能
  DMA ダイレクトメモリアクセス制御
  ADTM 高度な制御タイマー
  GPTM 汎用タイマー
  BCTM 基本タイマー
  USART 同期非同期通信
arduino関係
 ESP12関係
 (a)ESP-8266D1mini注意
PrP:その他  RS485ドライバー
 CP2102 BRIDGE
 WCH-LinkEエミュレーター
Pr:Wire 電線関係
Pr:Resistance 抵抗
Pr:Capacitor コンデンサ
Pr:Coil コイル
Pr:PassiveElmt 受動素子
Pr:Diode ダイオード関係
Pr:OPAMP オペアンプ関係
PrO:送受信機  Si4735
PrO:オペアンプ  LM324
 LM358
Pr:Tr トランジスタ関係
2SC1815
 リレードライバー設計
 アンプ設計
 発振器
TLP152
 TLP152テスト
TLP2361
 TLP2361テスト
TLP5754
 TLP5754テスト
Pr:Source 電源関係  ツェナーダイオード
 TL431
 LM317
PrS:Downモジュール
 EGS002_IR2110S
 SKU011012
 ACDC02
 XH_M299
 LM2596
 Mini360_MP23070N
 DROK
 WH140
PrS:UPモジュール
 MT3608
PrS:充電モジュール
 TP4056
Pr:Sensor_AD_時計等
PrS:電圧、電流
ADS1115 16bit4CH I2C A/D
 Hardware
 RaspberryPi_コマンド接続
 RaspberryPi_Python
 Arduino
 CH23V203 MounRiverStudioⅡ
INA226 I2C 直流電圧電流
 Hardware
 Arduino
 RaspberryPi_Python
WCS 電流ホール素子
 Hardware
PrS:温度、気圧、湿度、照度
BNE280 I2C 気圧,湿度,気温
 Hardware
 Arduino
 RaspberryPi_Python
BH1750 I2C 照度
 Hardware
 Arduino
 RaspberryPi_Python
DS18B20 1-Wire 温度計
 Hardware
 Arduino
 RaspberryPi_Python
PrS:時間、日時
DS3231 I2C 時計
 Hardware
 Arduino
 RaspberryPi_Python
PrS:表示器
MAR3953 320X480 3.95"
 概要と線や点を描く
 フォントを描く
SSD1306 I2C 0.96"OLED
 Hardware
 Arduino
 RaspberryPi_Python
Pr:Old Processor他

プログラムの手順

プログラムは MounRiver Studio Ⅱ を使用するので、予めインストールをすること。
インストールについてはメニューの『MounRiver Studioでプログラム』で説明しています。
プログラムの手順は下記の様になります。

 1. クロック速度の設定

 2. I/Oの設定

 3.~ プログラム

の手順でプログラムを進めて行きます。




1.クロック速度の設定

 1.1クロック速度とは

プログラムはシステムクロックと言うHi-Loの繰り返し信号によって読み取られ、実行する。
クロックが早ければ処理する時間が短くなるので、多くの処理ができる。

ただしクロックの速さとMPUの消費電流はクロックが早ければ消費電流は多くなる。
例えばクロック周波数FHCLK 8MHzだと1.21(mA)だが 144MHzでは12(mA)と増る。
500kHzだとなんと最低で0.31(mA)に抑えることができる。

電池などで駆動する物を作成するときはこの消費電流が装置設計の大きな要因となるので、一概に処理速度を早くするのではなく、プログラムの処理内容(数)により決める必要がある。

 1.2設定方法

速度の設定は system_ch32v20x.c に記載されている文を加工することにより簡単に設定ができます。
加工とは、コメントアウトを外すだけです。
下記の例は、内部発信子を使用してクロックを最大スピードの48MHZで使用します。

例:クロックの設定により、同じHi-Lo(遅延処理無し)繰り返しプログラムの処理時間

※遅延なしとはプログラムのHi-loの間でできるだけ早く繰り返す様にしたプログラムを言う。
 出力端子の負担抵抗は 無し の状態
48MHz_HIS 波形周波数= 8.13(MHz)
Hi-Lo処理時間61.5(ns) Lo-Hi処理時間61.5(ns)
  HSI_VALUE(8Mhz_HIS相当) 波形周波数= 1.351(MHz)
Hi-Lo処理時間370(ns) Lo-Hi処理時間370(ns)




2.I/Oの設定

 2.1設定概要

pinの入力・出力での選択項目は下表のとおり
入力出力
ハイインピーダンス
プルアップ
プルダウン
アナログ入力
オープンドレイン LO側駆動
LO,HIGH 両方駆動
代替機能として使用
信号の立ち上がり時間
実際にMUPのどんなレジスタが対象になるかはGPIO*_CFGLRを参照。

 2.2記述方法

設定プログラムは main.c に記載する。
このプログラムは初期設定なので、サブルーチンとして記載した。
下記例は PB0 を 出力 として設定しています。

サブルーチンの説明

① GPIOポートBのクロック供給を有効にする。
ポートBの他にAのクロック供給を有効にする場合は or すれば良い
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE);

② GPIO_InitTypeDefという構造体の変数 GPIO_InitStructure を宣言し、すべてのメンバーをゼロで初期化するC言語のコード。

③ GPIO_InitStructure という構造体の中に設定されている、ある特定のGPIOピンをGPIO_Pin_0として指定する。
ポートA,B,Cは⑥で設定することになるので注意すること。

④ 汎用入出力(GPIO)ピンのモードを「プッシュプル出力」に設定する。

その他設定内容は下表のとおり。
記述名説 明
GPIO_Mode_IN_FLOATING入力:高インピーダンス
GPIO_Mode_IPU入力:プルアップ
GPIO_Mode_IPD入力:プルダウン
GPIO_Mode_AIN入力:アナログ
GPIO_Mode_Out_0D出力:オープンドレイン LO側駆動
GPIO_Mode_Out_PP出力: LO,HIGH 両方駆動
GPIO_Mode_AF_0D代替機能出力:オープンドレイン LO側駆動
GPIO_Mode_AF_PP代替機能出力:LO,HIGH両方駆動

⑤ 汎用出力モードでの信号立ち上がり、立ち下がりの特性を周波数として設定する場所で、ここでは50MHzに設定しています。
その他設定内容は下表のとおり。
記述名説 明
GPIO_Speed_2MHz下の測定結果を参照
GPIO_Speed_10MHz
GPIO_Speed_50MHz

各設定値の立ち上がり・下がり時間の測定結果
 負担抵抗の有無で違いが有るかも参考に測定した
FREQ_48MHz 負担抵抗なし
Speed 50MHz
立ち上がり、下がり時間 12ns
FREQ_48MHz 負担抵抗430(Ω)
Speed 50MHz
立ち上がり、下がり時間 16ns
FREQ_48MHz 負担抵抗430(Ω)
Speed 2MHz
立ち上がり、下がり時間 20ns

⑥ ポートBの汎用入出力(GPIO)ピンを、GPIO_InitStructure という構造体で定義された設定内容に基づいて初期化する。

注意:直接レジスターに書き込む場合は GPIO*_CFGLRを参照。




3.信号出力プログラム

 3.1プログラム概要

プログラムのHi-loの間でできるだけ早く繰り返す様にしたプログラム

 3.2記述方法

書き方として幾つかの方法がある。
今回は 9種類の書き方でON,OFF時間の変化を測定した。
main.c に下記内容のプログラムを記載し、実行では //○番号 を外してコンパイル、プログラムの書き込みを行った。


プログラムの違いによるHi-Lo時間測定結果

測定条件  設定クロック:48MHz_HSI スピード:50MHz 負担抵抗:430Ω
No①
(1->0)516ns
(0->1)400ns
No②
(1->0)392ns
(0->1)294ns
No③⑤
(1->0)143ns
(0->1)147ns
No④⑥⑧⑨
(1->0)59ns
(0->1)66ns
No⑦
(1->0)164ns
(0->1)147ns

プログラムの違と速さ一覧

値の入力方法WriteBitOUTDRBSHR
or and xor 入力
1.095MHz
③⑤
3.44MHz

3.21MHz
ダイレクト入力
1.46MHz
④⑥
8.03MHz
⑧⑨
8.03MHz
WriteBit:WriteBit GPIO_WriteBit()関数を使用したプログラム
OUTDR:OUTDR レジスタに値を入れたプログラム
BBSHR:SHR レジスタのset(BS**)またはreset(BR**)に値を入れたプログラム
 各レジスターについては GPIO*_OUTDR および GPIO*_BSHR を参照

注意事項

 ※④⑥⑧⑨については同じポートで入出力など有った場合の影響について確認していない。特に④⑧は注意が必要。




4.信号入力プログラム

 4.1プログラム概要

ボタンを押している時に①100ms間隔でHi,Lo信号を繰り返し出力するものを作ります。
スピード設定 3項と同じ 48MHzHSI
出力ピンはPB0 3項と同じ Out_PP,50MHz,負担抵抗430Ω
入力ピンはPB3 ②プルアップ ※プルアップとは入力ピンに抵抗を通してVDDに接続する
       ③入力の検出
ボタンスイッチは PB3とGNDに接続する。 ④ポタンを押すことにより接点が閉じる。

 4.2記述方法

書き方は幾つかあるが、3項①で使用した GPIO_WriteBit 系の関数を使用する。
読み出し方は
GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_3);
を使用する。
また、100ms間隔でHi,Lo信号を繰り返し出力するため、処理を100(ms)停止する関数を使用する。
Delay_Ms(100);
だが、事前に初期化処理をするための処理をmain()に書き込む
Delay_Init();
以下にプログラムを示す。


プログラムの実行結果

青色が出力PB0
黄色が入力PB3




5.割り込みプログラム

 5.1割り込みの必要性

☆GoogleのAI先生のご意見を下記に記載します。
割り込み処理が必要となる主な理由は、CPUリソースの効率化、即応性の向上、省電力化の3つに集約される。
GPIOの状態変化(ボタンの押下やセンサーからの信号など)を検知する方法には、主に「ポーリング」と「割り込み」の2つがあります。
それぞれの特徴を理解することで、なぜ割り込み処理が必要なのかが明確になります。

ポーリング (Polling)

方法: CPUが定期的にGPIOの状態をチェックし、変化がないかを確認する。
デメリット:
CPUリソースの無駄: 変化が滅多に起こらない場合でも、CPUは常に状態を確認し続けるため、その分の処理能力を消費します。
即応性の遅延: 状態変化がチェックの周期とずれると、反応が遅れる可能性があります。
省電力性の低下: CPUを継続的に動かすため、バッテリー駆動機器などでは電力消費が大きくなります。

GPIO割り込み (Interrupt)

方法: GPIOの状態が変化した際に、ハードウェアが自動的にCPUへ信号を送り、実行中の処理を一時中断させて、専用の「割り込みハンドラ」を実行させる。
メリット:
CPUリソースの効率化: 普段はGPIOの状態を監視する必要がないため、CPUは他の重要なタスクに集中できます。
即応性の向上: 状態変化が起こった瞬間にCPUが通知されるため、迅速な応答が求められる場合に最適です。
省電力化: 待機中はCPUがスリープ状態になることができるため、大幅な消費電力の削減につながります。
どのような場合にGPIO割り込みが必要か?
具体的な応用例としては、以下のようなケースでGPIO割り込み処理の必要性が高まります。
応答性が重要なアプリケーション: ボタンの押下を検知して即座に処理を開始する、モーターの回転数変化にリアルタイムで対応するなど、遅延が許されない用途。
省電力設計: バッテリー駆動のIoTデバイスなどで、イベント発生時のみCPUを起動させて処理を行う。
マルチタスク処理: 複数のタスクを並行して実行している場合に、GPIOの状態監視にCPUが拘束されないようにする。
外部からのイベント通知: 外部のセンサーやデバイスからの信号を、メインプログラムの実行を妨げずに受け取る。

以上から例題をとおして、割り込み処理の必要性をみる。

 5.2割り込み無しのプログラム

5.2.1 要望する動作

メインで常に100msで一区切りの仕事(プログラム)が連続動作しており、ボタンを押した時・離した時に同時に違う仕事(プログラム)を実施するものを作成する。
具体的には下記動作のプログラムを割り込み無しで作成する。
 (1)100(ms)毎にHi-Loを繰り返す信号を出す。
  なお100(ms)はなにかの仕事(プログラム)をしているとみなし『Delay(100)』で処理する。
 (2)ボタンと押すと Lo信号、離すと Hi信号に変化する。
 各端子はPB0が(1)の出力、PB1が(2)の出力、PB3にスイッチを接続、スイッチの片方はGNDに接続する。

5.2.2 プログラム



5.2.3 プログラムの実行波形

黄色信号が PB3 で、スイッチを押すと Lo 、離すと Hi の信号が PB3 に入る。
水色信号が PB0 から出ている信号で、100(ms)毎にHi-Loを繰り返している。
ピンク色が PB1 から出ている信号だが・・

5.2.4 プログラムの問題点

PB1の信号はボタンスイッチを押せばLo、離せばHiになるはずだが、

PB1のピンク色信号が変化するのは、PB0の水色信号が変化する時になっている。

この動作はプログラムのとおりだが・・・
『要望する動作』では 『ボタンを押した時・離した時に同時に違う仕事』と記載されていることから要望と同じ様になっていない。
この動作を簡単に動作させるには割り込みを使用する。

 5.3 割り込みを使うプログラム

割り込み処理に不明の異常があり端子の役目を変更した。
 PB0 で、スイッチを押すと Lo 、離すと Hi の信号が P0 に入る。(オシロでは黄色信号)
 PA0 から出ている信号で、100(ms)毎にHi-Loを繰り返している。(オシロでは水色信号)
 PA1 から出ている信号。(オシロではピンク色)

5.3.1 プログラム概要

 ボタンを押した時、ボタンを離した時のプログラムを割り込み処理させる

5.3.2 プログラムの流れ

(1)GPIO_Init
 外部ピンの設定
(2)GPIO_EXTILineConfig
 GPIOピンを割り込みとして使えるように設定する。
(3)EXTI_Init
 GPIOピンからの信号を、CH32Vマイコン内のどの外部割り込みラインに接続するかを設定する。
(4)NVIC_Init
 特定の外部割り込みライン(例:EXTI Line 1)が、割り込みを発生させたときに、
 CPUに処理を依頼できるように設定(有効化)する。
 また、その割り込みの優先度を決定する。
(5)int main (void) {メイン処理}
(6)void EXTI0_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
 void EXTI0_IRQHandler(void){ 割り込み処理 }
  GPIOピンからの信号がトリガーとなり、割り込みが発生すると、
  CPUがNVICの設定に基づいて割り込みハンドラを呼び出す。

注意事項:

 GPIO_Pin_* 、EXTI_Line* 、GPIO_PinSource* 、EXTI*_IRQn 、EXTI*_IRQHandler の * は同じ種別番号です。

5.3.3 プログラム

 全てmain.cに記載しました。
 割り込みの㉑㉒㉓は 割り込みプログラムを記載した ch32v20x_it.c にまとめて記載した方が良いかも?

5.3.4 割り込みプログラム説明

プログラムの①〜⑦については、2.I/Oの設定 2.2記述方法で説明しているので割愛する。
※ただし③で PB2を出力に追加しているが、これは最後の※注意!で出た異常状態を見るために追加した。

割り込み処理することによりスイッチと同じ動作をすることが可能になった。


※注意! 調査必要

割り込みは現在 pin 0 以外は異常動作している。
以下プログラムは一部(関係するところ)を抜粋している

GPIext_InitStructure.GPIO_Pin = GPIO_Pin_*;
GPIO_EXTILineConfig (GPIO_PortSourceGPIOB, GPIO_PinSource*);
EXTI_InitStructure.EXTI_Line = EXTI_Line*;
NVIC_InitStructure.NVIC_IRQChannel = EXTI*x_IRQn;
void EXTI*_IRQHandler (void)

// 上記プログラム中の * 及び *x を 0 以外にすると割り込み処理が出来るようになるが
// 特に*x を0以外にすると main プログラムで下記異常がでる。

int main (void) {
 GPIO_INIT();
 while (1) {
  GPIOA->BSHR |= 0x00000001 ; //A
  GPIOA->BSHR |= 0x00000004 ; //B← B,Cが動作しない
  GPIOA->BSHR |= 0x00010000 ; //C
 } //←ただしWhileを含めコメントアウトするとプログラムは終了してしまう
   // ので While がある場合は Bで止まっているのでは無いようだ。
}

5.3.5 割り込み優先順位説明

1.NVIC_IRQChannelPreemptionPriority
役割: 実行中の割り込みを「中断させて」割り込むことができる優先度です。
動作: この値が小さい(優先度が高い)割り込みが発生すると、現在処理中の優先度が低い割り込みを一時停止し、即座に新しい割り込み処理を開始します(割り込みネスト)。
CH32V003の制約: ハードウェアの制限により、割り込みネストは最大 2レベル までです。

2.NVIC_IRQChannelSubPriority
役割: 同じ「先取り優先度」を持つ複数の割り込みが「同時に」発生した際の実行順序を決めます。
動作: すでに実行中の割り込みを中断させることはできません。あくまで待ち状態の割り込みの中での優先順位です

3.具体的な設定値
項目備考
Preemption0 ~ 1 0が最高優先、1が最低優先
Sub 0 ~ 1同上

4.実装時の注意点
割り込みを設定する前に、2ビットの優先度領域をどのように「先取り」と「サブ」に振り分けるかを NVIC_PriorityGroupConfig() で指定する必要があります。
(1) NVIC_PriorityGroup_1
先取り優先度(0-1)、サブ優先度(0-1) に1ビットずつ割り当てます(一般的)。
(2) NVIC_PriorityGroup_2
すべてを先取り優先度(0-3)に割り当てます(サブ優先度は使わない)。
※CH32V003には NVIC_PriorityGroup_2 はありません。

5.例
割り込みPreemptionSub理由

TIM1

00最も高い。PWM生成や高速サンプリングなど、厳密な同期が必要なため。

USART1 Rx

01受信漏れを防ぐため高めに設定。
USART1のボーレートが非常に高い(115200bps以上など)場合は、優先度を上げることを検討。

TIM2

10汎用タイマー処理。USART受信よりは許容度がある場合が多い。

USART1 Tx(DMA)

11送信は多少遅延してもデータの整合性に影響しないため、優先度を下げます。
Preemption (横取り):Sub (同一優先度内順位)





































更新日 2025/12/23 11:27  管理者 平林 剛Hirabayashi Takeshi