STM32シリアルポートアイドル割り込み+ DMAがMPU6050データを読み取る

STM32シリアルポートアイドル割り込み

データを受信するプロセス:

DMAを受信するシリアルポートは、初期化されるとオン状態になり、データが到着するまで待機します。初期構成中に構成が設定されている限り、ソフトウェアで何もする必要はありません。
データデータ受信完了
の判定ここで受信完了の判定は、シリアルポートのアイドル割り込みにより行われます。つまり、シリアルデータの流れが停止するとIDLE割り込みが発生します。この割り込みでは、次のことが行われます。

  1. DMAチャネルを受信するシリアルポートを閉じるには、次の2つの理由があります:a。後続のデータ受信を防ぎ、干渉を引き起こします。b。4番目のポイントであるDMAの再構成と割り当てを容易にします。
  2. 受信完了フラグを立てる
  3. 受信バッファー内のデータを処理する
  4. 次にDMAが受信するデータバイト数をリセットします。ここでは、DMAレジスタの受信カウント値をリセットします。この数は、受信可能なバイト数以上でなければなりません。それ以外の場合、DMA受信カウンターが0にデクリメントするときそのとき、カウント値が再度リロードされ、カウントが再循環されるため、受信バッファー内のデータは上書きされて失われます。
  5. DMAチャネルをオンにして、次のデータ受信を待ちます。DMA関連のレジスタ構成への書き込み(第4条の書き込みカウント値など)は、DMAをオフにした状態で実行する必要があります。
    STM32のIDLE割り込みは、シリアルポートでデータ受信がない場合は常に生成されるわけではなく、IDLEフラグビットがクリアされている場合は、最初のデータを受信して​​から開始する必要があることを説明します。トリガーされ、受信データが中断され、データが受信されなくなると、IDLE割り込みが生成されます。IDLEビットは、RXNEビットが設定される(つまり、アイドルバスが再度検出される)まで、再度Highに設定されることはありません。RXNE受信割り込みをオンにできないため、割り込み数が減少します。
    ここに画像の説明を挿入
void My_UART_Init(void)
{
    
    
    GPIO_InitTypeDef GPIO_InitStruct;
    USART_InitTypeDef USART_InitStruct;
    NVIC_InitTypeDef NVIC_InitStruct;
    DMA_InitTypeDef DMA_InitStruct;

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);      // 使能DMA
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);   // 使能GPIOA
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);   // 使能时钟 复用USART

    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz;
    GPIO_Init(GPIOA,&GPIO_InitStruct);  //初始化 USART_TX 即 GPIOA.9 

    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz;
    GPIO_Init(GPIOA,&GPIO_InitStruct);          //初始化 USART_RX 即 GPIOA.10

    USART_InitStruct.USART_BaudRate = 115200;
    USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    USART_InitStruct.USART_Parity = USART_Parity_No;
    USART_InitStruct.USART_StopBits = USART_StopBits_1;
    USART_InitStruct.USART_WordLength = USART_WordLength_8b;
    USART_Init(USART1,&USART_InitStruct);   //初始化 USART

//  USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);  // 开启 USART 接收缓冲区非空中断
//  USART_ITConfig(USART1, USART_IT_TXE, ENABLE);   // 开启 USART 发送缓冲区空中断

    USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);  //开启 USART1 总线空闲中断
    USART_Cmd(USART1, ENABLE);//使能USART中断

    DMA_DeInit(DMA1_Channel5);
    DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)(&USART1->DR);    //外设--->内存
    DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)RxBuffer;
    DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStruct.DMA_BufferSize = BufferSize;
    DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC;
    DMA_InitStruct.DMA_M2M = DMA_M2M_Disable;
    DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
    DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    DMA_InitStruct.DMA_Priority = DMA_Priority_Medium;
    DMA_InitStruct.DMA_Mode = DMA_Mode_Normal;
    DMA_Init(DMA1_Channel5, &DMA_InitStruct);

    DMA_Cmd(DMA1_Channel5, ENABLE);
    USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE);              // 使能 USART1接收DMA

    NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn;
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0x01;   //抢占优先级 2位 00 01 10 11
    NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0x01;          //响应优先级 2位 00 01 10 11
    NVIC_Init(&NVIC_InitStruct);                                //初始化中断
}

ここに画像の説明を挿入
MCUがUSARTを介して外部から送信されたデータを受信すると、メインプログラムは手順①②③を無視でき、DMAは受信データをバッファRxBufferに直接書き込みます。このとき、プログラムは受信割り込みに入りません。受信が完了すると、受信アイドル割り込みが生成され、割り込みサービス関数で受信完了フラグが1に設定され、受信バッファー内のデータ長が計算され、割り込みビットがクリアされ、DMAが無効になり、データの処理時にデータの受信を防止します。メインプログラムで受信完了フラグが1に設定されていることが検出され、データ処理プログラムに入り、受信完了フラグが0に設定され、次にDMAが受信するデータバイト数をリセットし、DMAが受信データ状態になるようにします。

void USART1_IRQHandler(void)
{
    
    
    uint8_t clear = clear;  // 用来消除编译器的“没有用到”的提醒
    uint8_t data = 0;

    if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET)
    {
    
    
        clear = USART1->SR;
        clear = USART1->DR;

//      RxCounter = BufferSize - DMA1_Channel5->CNDTR;//缓存中的字节数
        RxCounter = BufferSize - DMA_GetCurrDataCounter(DMA1_Channel5);//缓存中的字节数

//      USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);

        RxStatus = 1;   //标记接收到一帧
        USART_ClearITPendingBit(USART1, USART_IT_IDLE); // 清除空闲中断

        DMA_Cmd(DMA1_Channel5, DISABLE);                // 停止DMA,清除DMA缓存
    }
}

int main(void)
{
    
    
    uint8_t i = 0;

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);             // 初始化中断优先级分组

    My_UART_Init();

    while(1)
    {
    
    
        if(RxStatus == 1)
        {
    
    
            RxStatus = 0;
            i = 0;

            while(RxCounter--)
            {
    
    
                USART_SendData(USART1, RxBuffer[i++]);
                while(USART_GetFlagStatus(USART1, USART_FLAG_TC) != SET);
            }

            memset(RxBuffer, 0, i); // 清除缓存
            RxCounter = 0;

//          DMA1_Channel5->CNDTR = BufferSize;
            DMA_SetCurrDataCounter(DMA1_Channel5, BufferSize);
            DMA_Cmd(DMA1_Channel5, ENABLE);     
        }
    }
}

DMAの紹介

DMAの定義

DMA(ダイレクトメモリアクセス、DMA)は、コンピュータサイエンスにおけるメモリアクセス技術です。これにより、特定のコンピューターの内部ハードウェアサブシステム(コンピューター周辺機器)が、CPUをバイパスせずにシステムメモリを個別に読み書きできます。同じ程度のCPU負荷の下で、DMAは高速データ転送方式です。これにより、CPUからの多数の割り込み要求に依存することなく、さまざまな速度のハードウェアデバイスが通信できます。

DMAの用途は何ですか?

ダイレクトメモリアクセスは、周辺機器とメモリ間、またはメモリとメモリ間の高速データ転送を提供するために使用されます。CPUの介入がなくても、DMAを介してデータをすばやく移動できます。これにより、他の操作のためのCPUリソースが節約されます。

DMAリソースはいくつありますか?

DMAコントローラは2つあり、DMA1には7チャネル、DMA2には5チャネルがあります。

データはどこから送信されますか?

  • 周辺機器はSRAMに行き(I2C / UARTなどでデータを取得し、SRAMに送信します)、SRAM
    の2つの領域間を移動します。
  • 周辺機器から周辺機器へ(ADCはデータを読み取り、TIM1に送信して、さまざまなPWMデューティサイクルを生成するように制御します);
  • SRAMからペリフェラル(SRAMに保存されたデータはDACに送信され、さまざまな波形を生成します);

DMA転送できるデータ量はどれくらいですか?

DMAの従来の概念は大量のデータの送信に使用されますが、STM32ではその概念が拡張されており、多くの場合、高速がそのアプリケーションの焦点であると理解しています。データは1〜65535です。

DMAコントローラーとアービター

現在、ますます多くのシングルチップマイクロコンピュータがDMA技術を採用して、周辺機器とメモリ間またはメモリ間で高速データ転送を提供しています。CPUがこの転送アクションを開始すると、転送アクション自体はDMAコントローラ実装して完了する。STM32にはDMAコントローラがあり、7つのチャネルがあり、各チャネルはメモリアクセスを要求する1つ以上のペリフェラルの管理専用で、アービタ各DMA要求の優先順位を調整します。

DMAコントローラとCortex-M3コアは、システムデータバスを共有して、直接メモリデータ転送を実行します。CPUとDMAが同じターゲット(RAMまたは周辺機器)に同時にアクセスすると、DMA要求によりCPUがシステムバスにアクセスするのを数サイクル停止し、バスアービターが循環スケジューリングを実行して、CPUがシステムバス(メモリ)の少なくとも半分を取得できるようにします。または周辺機器)帯域幅。

イベントが発生すると、ペリフェラルはリクエスト信号をDMAコントローラに送信します。DMAコントローラは、チャネルの優先度に従って要求を処理します。DMAコントローラがペリフェラルへのアクセスを開始すると、DMAコントローラは直ちにペリフェラルに応答信号を送信します。DMAコントローラから応答信号を受信すると、ペリフェラルはその要求をすぐに解放します。ペリフェラルがこの要求を解放すると、DMAコントローラは同時に応答信号をキャンセルします。さらに要求が発生した場合、ペリフェラルは次の処理を開始できます。

コード表示

シリアルポートアイドル+ HALライブラリに基づくDMAメイン受信コード

以下はヘッダーファイルです

#ifndef DMAT_H
#define DMAT_H
#include "stm32f1xx_hal.h"
#include "usart.h"

extern uint8_t usart2_rx_buffer[33];
extern uint8_t usart3_rx_buffer[25];
void MyU2Init(void);
void MyU3Init(void);
void USART2Handle(void);
void USART3Handle(void);
void MyUsartHandle(UART_HandleTypeDef *HUART);
#endif

以下はソースファイルです

#include "dmat.h"

uint8_t usart2_rx_buffer[33]={
    
    0};
uint8_t usart3_rx_buffer[25]={
    
    0};

float ROLL_ANGLE=0;
float PITCH_ANGLE=0;
float YAW_ANGLE=0;
void MyU2Init(void)
{
    
    
	__HAL_UART_CLEAR_IDLEFLAG(&huart2);
	__HAL_UART_ENABLE_IT(&huart2,UART_IT_IDLE);
	HAL_UART_Receive_DMA(&huart2,usart2_rx_buffer,33);
}

void MyU3Init(void)
{
    
    
	__HAL_UART_CLEAR_IDLEFLAG(&huart3);
	__HAL_UART_ENABLE_IT(&huart3,UART_IT_IDLE);
	HAL_UART_Receive_DMA(&huart3,usart3_rx_buffer,25);
}
//可以在里面加上想要的功能
//以及数据处理的代码
//这是采用串口+DMA+空闲中断来处理串口接收的数据
void USART2Handle(void)
{
    
    
	if(usart2_rx_buffer[0]==0x55&&usart2_rx_buffer[11]==0x55&&usart2_rx_buffer[22]==0x55)
	{
    
    
		//总共33个字节的数据,每11个字节的数据算一个数据包,三个数据包分别是加速度包,角速度包和角度包
		if(usart2_rx_buffer[23]==0x53)
		{
    
    
			//下面的数据是针对角度包来解析的,得到三个角度
			ROLL_ANGLE=((int16_t)(usart2_rx_buffer[25]<<8|usart2_rx_buffer[24]))/32768.0*180;
			PITCH_ANGLE=((int16_t)(usart2_rx_buffer[27]<<8|usart2_rx_buffer[26]))/32768.0*180;
			YAW_ANGLE=((int16_t)(usart2_rx_buffer[29]<<8|usart2_rx_buffer[28]))/32768.0*180;
		}
	}
}
void USART3Handle(void)
{
    
    
}
void MyUsartHandle(UART_HandleTypeDef *HUART)
{
    
    
	 if(HUART==&huart2)
	{
    
    
		
	if(__HAL_UART_GET_FLAG(HUART,UART_FLAG_IDLE))
	{
    
    
		
		__HAL_UART_CLEAR_IDLEFLAG(HUART);
		HAL_UART_DMAStop(HUART);
		USART2Handle();
		HAL_UART_Receive_DMA(HUART,(uint8_t*) usart2_rx_buffer,33);
		
	}
  }
	else if(HUART==&huart3)
	{
    
    
		if(__HAL_UART_GET_FLAG(HUART,UART_FLAG_IDLE))
	{
    
    
		__HAL_UART_CLEAR_IDLEFLAG(HUART);
		HAL_UART_DMAStop(HUART);
		USART3Handle();
		HAL_UART_Receive_DMA(HUART,(uint8_t*) usart2_rx_buffer,25);
	}
	}
}

おすすめ

転載: blog.csdn.net/sharpzhen/article/details/108720110