P2 NBIOT(DMA+空閒中斷)

1.相關概念解釋

1.1串口透傳

  • 日常拿到某個模組以後咱們每每經過USB-TTL芯片將模組與電腦相連,進而對模組狀態進行檢測或者控制模組
  • 串口透傳則是將模組與單片機相連,以後再經過USB-TTL將單片機與電腦相連,經過單片機對模組進行控制,即單片機至關於中間商
  • 具體作法是:模組與單片機之間經過串口2通訊,單片機與電腦經過串口1通訊,在單片機內部經過DMA+空閒中斷對數據進行轉發

1.2空閒中斷

  • 空閒中斷就是每接收到一條完整的數據就會置位空閒標誌位,咱們只須要判斷空閒標誌位是否置一就能知道是否是接收到了一條完整的數據
  • 使用空閒中斷可減少進入中斷的次數,進而減少CPU負擔

1.3DMA

  • DMA(Direct Memory Access:直接內存存取)是一種能夠大大減輕CPU工做量的數據轉移方式
  • 比如CPU是BOSS,DMA是祕書,某天公司收到了一大批貨物,在沒有祕書的狀況下須要BOSS停下手中的工做親自去將貨物搬到倉庫,而有了祕書後,BOSS只須要告訴祕書有貨物到了,讓祕書去搬運貨物,而BOSS則繼續處理本身的事情,當祕書搬完後再通知BOSS便可
  • DMA的做用就是實現數據的直接傳輸,而去掉了傳統數據傳輸須要CPU寄存器參與的環節,從內存的某一區域傳輸到內存的另外一區域
  • 當用戶將參數設置好,主要涉及源地址,目標地址,傳輸數據量這三個,DMA控制器就會啓動數據傳輸,傳輸的終點就是剩餘傳輸數據量爲0(循環傳輸不是這樣的),換句話說只要剩餘傳輸數據量不是0,並且DMA是啓動狀態,那麼就會發生數據傳輸。

2.經過cubemx使用DMA+空閒中斷

2.1配置cubemx

  • 選擇芯片
  • 設置調試方式

  • 配置時鐘

  • 配置串口1

  • 配置串口2

  • 配置控制引腳

  • 設置時鐘

  • 配置輸出選項

  • 輸出工程

  • 至此,基本外設已經配置完畢,下面就開始愉快地寫代碼

2.2軟件設置

2.2.1串口初始化

  • 開啓串口2接收中斷與空閒接收中斷
  • 清除中斷,由於stm32默認上電會產生一個空閒中斷,因此須要清除之
  • 打開串口DMA接收
void EnableUsart_IT(void)
{
    __HAL_UART_ENABLE_IT(&huart2, UART_IT_RXNE);//開啓串口2接收中斷
    __HAL_UART_ENABLE_IT(&huart2, UART_IT_IDLE);//開啓串口2空閒接收中斷
    __HAL_UART_CLEAR_IDLEFLAG(&huart2);         //清除串口2空閒中斷標誌位
    HAL_UART_Receive_DMA(&huart2,Usart2type.Usart2DMARecBuffer,USART2_DMA_REC_SIE);  //使能DMA接收
}

2.2.2串口中斷處理函數

  • 判斷是否爲空閒中斷
  • 清除中斷標誌位
  • 中止DMA接收
  • 獲取DMA接收數據的長度
  • 串口回調函數,在其中將DMA接收的BUFF數據拷貝到RecBUFF裏面
  • 開啓DMA接收
void USART2_IRQHandler(void)
{
  /* USER CODE BEGIN USART2_IRQn 0 */
  uint32_t temp;
  if(__HAL_UART_GET_FLAG(&huart2, UART_FLAG_IDLE) == SET)	//若是串口2觸發空閒中斷
  {
	  
	  __HAL_UART_CLEAR_IDLEFLAG(&huart2);	//清除串口2空閒中斷標誌位
	  HAL_UART_DMAStop(&huart2);            //關閉DMA
	  
	  //讀取一下兩個寄存器方可清除DMA接收中斷
	  temp = huart2.Instance->SR;			//清除SR狀態寄存器(F0系列爲ISR)
	  temp = huart2.Instance->DR;			//讀取DR數據寄存器(F0系列爲RDR)用來清除中斷
	  
	  temp = hdma_usart2_rx.Instance->CNDTR;//獲取DMA中未傳輸的數據個數
	  Usart2type.UsartDMARecLen = USART2_DMA_REC_SIE - temp;           //總計數減去未傳輸的數據個數,獲得已經接收的數據個數
	  HAL_UART_AbortCpltCallback(&huart2);		//串口接收回調函數

  }
  /* USER CODE END USART2_IRQn 0 */
  HAL_UART_IRQHandler(&huart2);
  /* USER CODE BEGIN USART2_IRQn 1 */
  HAL_UART_Receive_DMA(&huart2,Usart2type.Usart2DMARecBuffer,USART2_DMA_REC_SIE);  //從新打開DMA接收
  /* USER CODE END USART2_IRQn 1 */
}

2.2.3串口回調函數

  • 判斷是否爲串口2
  • 是否有未讀數據

有未讀數據則從地址0+old_len開始獲取DMA接收區的數據函數

無則從地址0開始獲取DMA接收區的數據oop

  • 清空DMA接收區
  • 置位數據包接收標誌位
/*
功能:串口回調函數,用來搬移數據
*/
void HAL_UART_AbortCpltCallback(UART_HandleTypeDef *huart)
{
	//printf("*******in callback*******\r\n");
    if(huart->Instance == USART2)
    {
        if(Usart2type.UsartRecLen>0)            
        {
            memcpy(&Usart2type.Usart2RecBuffer[Usart2type.UsartRecLen],Usart2type.Usart2DMARecBuffer,Usart2type.UsartDMARecLen); //轉存到待處理區域
            Usart2type.UsartRecLen +=  Usart2type.UsartDMARecLen;
        }
        else
        {
            memcpy(Usart2type.Usart2RecBuffer,Usart2type.Usart2DMARecBuffer,Usart2type.UsartDMARecLen);                          //轉存到待處理區域
            Usart2type.UsartRecLen =  Usart2type.UsartDMARecLen;
        }
		printf("%s\r\n", Usart2type.Usart2DMARecBuffer);
        memset(Usart2type.Usart2DMARecBuffer, 0x00, Usart2type.UsartDMARecLen);                                     //先清空DMA緩衝區
        Usart2type.UsartRecFlag = 1;	//置位標記,表示串口2接收到數據
    }
}

2.2.4主函數測試

int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_USART1_UART_Init();
  MX_USART2_UART_Init();
  /* USER CODE BEGIN 2 */
  EnableUsart_IT();
  
  printf("System init OK!!\r\n");
  
  //模組開機
  HAL_GPIO_WritePin(NB_PWK_GPIO_Port, NB_PWK_Pin, GPIO_PIN_SET);
  HAL_Delay(2500);
  HAL_GPIO_WritePin(NB_PWK_GPIO_Port, NB_PWK_Pin, GPIO_PIN_RESET);
  
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
	  memset(Usart2type.Usart2RecBuffer, 0x00, USART2_REC_SIE);
	  HAL_UART_Transmit(&huart2, (uint8_t*)"ATI\r\n", strlen("ATI\r\n"), 0xff);
	  printf("ATI\r\n");
	  HAL_Delay(2000);
	  if(Usart2type.UsartRecFlag == 1)
	  {
		  //printf("Usart2 rec is:%s\r\n", Usart2type.Usart2RecBuffer);
		  Usart2type.UsartRecFlag = 0;
		  Usart2type.UsartRecLen = 0;
	  }
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}
  • 接線

VCC------stm32 V3測試

ui

VCC------cp2102 3V33d

相關文章
相關標籤/搜索