在使用stc8a8k64d4官方库函数时遇到了问题

佬们好,stc8a8k64d4,用的stc官方库函数,设置好了dma_adc转运,我判断dmaadcflag是否置1发送串口消息,但是一直发不出去(我很确定是dmaadcflag没有置1的问题,因为没了这个判断串口发送是正常的),然后我跟官方例程也对了很久,没看出来有啥问题。如图所示,然后我dma转运到的是u16的十六个元素的数组。查了三个小时没查出来啥问题,我就是个苦学生,求求了。

中断の確認を重点的にやってください!NVIC_DMA_ADC_Initは有効にしていますが、対応する割り込みサービス関数はちゃんと書きましたか?STCの割り込み関数名は固定されており、自分で勝手に書いてはいけません。間違えると割り込みに入ることができず、フラグも当然「1」になりません。また、割り込み番号を他のものと混同しないように注意してください。

この問題は、STC8A8K64D4のDMA-ADC開発において非常に典型的な初心者向けの落とし穴です。以下では重要度の高い順に問題点とその解決策を分解して説明します。順番に確認すれば確実に解決できます。


一、最も重要な必須チェック項目(90%の確率でここに原因あり)

1. ADCのDMA有効化が必須。これをしないとADCはDMA転送をトリガーしない

あなたのADC初期化コードには、まったくADCのDMA機能が有効になっていません!
STC8AシリーズのADCをDMAと連携させるには、ADC変換終了時に自動的にDMAを起動させる必要があります。この設定がなければ、ADCが変換を終えてもDMAは一切動きません。そのため、転送完了割り込みも発生せず、フラグも決してセットされません。

  • 修正方法: ADC初期化構造体にDMA有効化の設定を追加
ADC_InitStructure.ADC_DMA_Enable = ENABLE; // 核心:ADCによるDMAトリガー機能を有効化
  • もしご使用のライブラリにこのメンバーがない場合は、直接レジスタ操作を行ってください:
ADC_CONTR |= 0x40; // ADC_DMA_ENビットをセット(正確なビット位置はチップマニュアルで確認)

2. DMA初期化の設定ミス — 目的バッファアドレスが設定されていない

DMA_ADC_InitStructure.DMA_Buffer = ADC_Result_Once; という記述は完全に誤りです。

  • ADC_Result_Once転送モードのマクロ(シングルトランスファー)であり、バッファアドレスではありません

  • 実際に定義したu16型配列のアドレスをDMAに設定していないため、DMAはADC結果をどこに保存すべきか分からず、正常に転送できません。

  • 正しいDMA初期化コードの例(STC公式標準ライブラリ準拠):

u16 AdcResultBuf[16]; // ご質問にある16要素のu16配列

DMA_ADC_InitStructure.DMA_Enable = ENABLE;
DMA_ADC_InitStructure.DMA_Channel = 0x0003; // ADC対応DMAチャンネル3(設定は正しい)
DMA_ADC_InitStructure.DMA_Mode = ADC_Result_Once; // 単発転送モード → モードはここに指定
DMA_ADC_InitStructure.DMA_Times = 16; // 転送回数は配列長と一致させる必要あり(8回は誤り)
DMA_ADC_InitStructure.DMA_AdcResult = AdcResultBuf; // 核心:目的配列のアドレスを代入

3. フラグ変数にはvolatileが必要。かつ割り込み関数内で正しくセットする必要あり

割り込み関数とDmaADCFlagの定義を貼っていませんが、これが最も見落とされやすいポイントです。

  • 問題1:DmaADCFlagが割り込み内で変更され、main関数内で判定される場合、必ずvolatileキーワードを付ける必要があります。これを付けないと、コンパイラが最適化により「この変数は変わらない」と判断し、if文が無視されます。つまり、割り込みで1にセットしても、main関数側では変化が見えません。

  • 問題2:正しいDMA-ADC割り込みサービスルーチン(ISR)を記述し、その中でフラグをセットしなければ、フラグは常に0のままです。

  • 正しい記述例:

volatile u8 DmaADCFlag = 0; // 必ずvolatileを付ける!!!

// 割り込みサービスルーチン。interrupt後の番号は公式ライブラリと一致させる(通常INT_NO_DMA_ADC、値は22)
void DMA_ADC_Isr(void) interrupt INT_NO_DMA_ADC
{
    DmaADCFlag = 1; // 転送完了 → フラグをセット
}

二、優先度は低いが修正必須の問題

1. DMA転送回数と配列長が一致していない

配列は16個のu16要素と明言しているのに、コード上はDMA_Times=ADC_8_Times(8回)と設定されています。この不一致があると、前述のすべての設定が正しくても、半分のデータしか転送されず、その後の処理も異常になります。必ず配列長と一致させる必要があります。

2. ADC変換モードとDMAトリガーの連携

現在のADCは変換モードが設定されておらず、デフォルトの単発変換モードになっています。DMA転送が1回終わると、次回以降のADC変換を手動で再開しない限り、再度変換は行われず、DMAも再びトリガーされません。

  • 推奨:連続変換モードに変更。ADC初期化時に以下を追加:
ADC_InitStructure.ADC_Conversion = ADC_CONVERSION_CONTINUOUS; // 連続変換モードを有効化
  • または、毎回DMAを再トリガーするたびに、手動でADCを起動:
DMA_ADC_TRIG();
ADC_START(); // 公式ライブラリのADC起動マクロ(使用中のライブラリに合わせる)

三、トラブルシューティングの推奨手順

  1. 最初に、フラグ変数にvolatileを追加し、正しい割り込みサービスルーチンを記述して、割り込みが正しく発生することを確認する。
  2. ADC初期化コードに、ADCのDMA有効化設定を追加。
  3. DMA初期化コードを修正し、転送モード・転送回数・目的配列アドレスを正しく設定。
  4. 全体割り込みEA=1およびDMA割り込みの有効化が正しく設定されているか確認。
  5. 最初は簡略化してテスト:転送回数を1に、配列を1要素にして、まずは単発転送が通ることを確認。その後、16回に戻す。