九、MyDebugger
已經學習了usart和DMA,因爲後面的學習,最好有一個直觀點的人性化的顯示終端。可以通過串口將數據和文字信息發送往電腦,然後在上位機軟件上觀察數據以及調試信息。爲此,我寫了一個文件,以供日後調試之用,命名爲MyDebugger。
首先,參照之前的程序,略加修改,將USART的接收功能全部去掉,DMA的配置分開,獨立寫成一個配置DMA的函數USART3_DMA_config(),把發送的部分寫到MyDebugger_Message(char *str_address, unsigned int str_len)函數內,很簡單地實現了一個發送字符消息的函數。然後寫一個操作板子上指示燈的函數,用以日後指示調試信息。具體的實現,請看下程序(實現MyDebugger的驗證程序)。
把驗證程序分離寫成頭文件形式。方便以後其他工程使用。把程序稍作修改,利用條件編譯,爲以後可能的添加其他通信方式提供方便。要使用USART3作爲調試通信方式,必須先定義宏MyDebug_with_USART3,如下圖所示:
實現MyDebugger的驗證程序:
/*********************************************
標題:MyDebugger
軟件平臺:IAR for ARM6.21
硬件平臺:stm32f4-discovery
主頻:168M
描述:實現一個調試工具
author:小船
data:2012-02-04
**********************************************/
#include <stm32f4xx.h>
#include <stdbool.h>
/******LED宏定義*******/
#define green 0x00001000
#define orange 0x00002000
#define red 0x00004000
#define blue 0x00008000
/******全局變量及類型聲明*******/
bool USART_DMA_Completed;
enum LED_State {on, off, turn};
/******函數聲明*******/
void LEDs_Init(void);
void USART3_DMA_config(void);
void USART3_config(void);
bool MyDebugger_Message(char *str_address, unsigned int str_len);
void MyDebugger_LEDs(uint32_t LED, enum LED_State state);
void main ()
{
SysTick_Config(SystemCoreClock / 1000); //設置systemtick一毫秒中斷
SCB->AIRCR = 0x05FA0000 | 0x400; //中斷優先級分組 搶佔:響應=3:1
LEDs_Init();
USART3_DMA_config();
USART3_config();
USART_DMA_Completed = 1;
while(1)
{
MyDebugger_Message("My name is Xian Yongwen\n",
sizeof("My name is Xian Yongwen\n")/sizeof(char));
MyDebugger_Message("廣東石油化工學院\n",
sizeof("廣東石油化工學院\n")/sizeof(char));
}
}
/*********************************************
函數名:MyDebugger_Message
參數:char *str_address :要發送的字符串地址
unsigned int str_len :字符串的長度
返回值:bool 是否操作成功
功能:通過USART3發送信息
**********************************************/
bool MyDebugger_Message(char *str_address, unsigned int str_len)
{
if( USART_DMA_Completed ) //之前數據已經發送完成
{
DMA1_Stream3->CR &= 0xFFFFFFFE; //除能DMA1_Stream3
while(DMA1_Stream3->CR & 0x00000001); //確保DMA可以被設置
DMA1->LIFCR |= 0x0f800000; //傳送前清空DMA1_Stream3所有中斷標誌
DMA1_Stream3->M0AR = (uint32_t)str_address; //設置內存地址
if((USART3->SR & (1<<7))) //發送數據寄存器空
{
USART3->CR3 &= ~(1<<7);//usart3 dma發送模式除能
USART_DMA_Completed = 0;
DMA1_Stream3->NDTR = str_len; //設置dma傳輸數據的數量
DMA1_Stream3->CR |= 1;//使能dma
USART3->CR3 |= (1<<7);//usart3 dma發送模式使能
return true;
}
}
return false;
}
/****************************************
函數名:MyDebugger_LEDs
參數:uint32_t LED :要操作哪些LED
enum LED_State state :作何操作
返回值:無
功能:改變LED的狀態
****************************************/
void MyDebugger_LEDs(uint32_t LED, enum LED_State state)
{
uint32_t tmp;
switch (state)
{
case on:
{
GPIOD->BSRRL |= LED;
break;
}
case off:
{
GPIOD->BSRRH |= LED;
break;
}
case turn:
{
tmp = (~GPIOD->ODR) & LED;
GPIOD->ODR &= ~LED;
GPIOD->ODR |= tmp;
break;
}
}
}
/****************************************
函數名:USART3_DMA_config
參數:無
返回值:無
功能:DMA1數據流3與usart3關聯的相關配置
****************************************/
void USART3_DMA_config(void)
{
RCC->AHB1ENR |= (1<<21); //使能DMA1時鐘
DMA1_Stream3->CR &= 0xFFFFFFFE; //除能DMA1_Stream3
while(DMA1_Stream3->CR & 0x00000001);//確保DMA可以被設置
DMA1->LIFCR |= 0x0f800000;//傳送前清空DMA1_Stream3所有中斷標誌
DMA1_Stream3->PAR = (uint32_t)&USART3->DR;//設置外設地址USART3->DR地址0x40004804
//設置內存地址
DMA1_Stream3->FCR &= 0x00000000;
DMA1_Stream3->FCR |= (1<<7);//設置fifo
/*
設置dma通道4,即usart3tx
優先級最高
傳輸方向內存到外設
內存遞增模式
傳輸完成中斷使能
*/
DMA1_Stream3->CR |= (0x08000000 | 0x00030000 | (1<<6)
| (1<<10) | (1<<4) | (1<<2)|(1<<1));
NVIC->IP[14] = 0xA0;
NVIC->ISER[0] |= (1<<14);
}
/**************************
函數名:USART3_config
參數:無
返回值:無
功能:配置usart3
************************/
void USART3_config(void)
{
RCC->APB1ENR |= (1<<18); //使能usart3時鐘
RCC->AHB1ENR |= 0x00000008; //使能GPIOD時鐘
USART3->BRR = 0x0000016C; //波特率115200
/*
使能usart3
usart3發送使能
8bit
一位停止位
無校驗
*/
USART3->CR1 |= ( ( 1<<13 ) | ( 1<<3 ) );
GPIOD->AFR[1] |= 0x00000077;//選擇PD8,9複用功能
GPIOD->MODER &= 0xFFF0FFFF; //設置PD8,9,複用模式
GPIOD->MODER |= 0x000A0000;
GPIOD->OSPEEDR &= 0xFFFCFFFF; //PD8速度50m
GPIOD->OSPEEDR |= 0x00020000;
GPIOD->PUPDR &= 0xFFFCFFFF; //PD8
GPIOD->PUPDR |= 0x00010000;
}
/****************************************
函數名:LEDs_Init
參數:無
返回值:無
功能:初始化板子上的LED
****************************************/
void LEDs_Init(void)
{
RCC->AHB1ENR |= 0x00000008; //使能GPIOD時鐘
GPIOD->MODER &= 0x00FFFFFF; //設置PD12,13,14,15輸出
GPIOD->MODER |= 0x55000000;
GPIOD->OTYPER &= 0xFFFF0FFF; //設置PD12,13,14,15推輓輸出
GPIOD->OSPEEDR &= 0x00FFFFFF; //PD12,13,14,15 速度100m
GPIOD->PUPDR &= 0x00FFFFFF; //PD12,13,14,15 無上拉無下拉
GPIOD->BSRRH = 0xf000; //reset register GPIOx_BSRRH, write only
//set register GPIOx_BSRRL, write only
}
void DMA1_Stream3_IRQHandler(void)
{
if(DMA1->LISR & 0x08000000)//DMA傳輸完成
{
USART_DMA_Completed = 1;
DMA1->LIFCR |= 0x08000000;//清除中斷標誌
}
if(DMA1->LISR & 0x03000000) //如果發生傳輸錯誤或直接模式錯誤,亮橙色LED
{
MyDebugger_LEDs( orange, on);
DMA1->LIFCR |= 0x03000000;
}
if(DMA1->LISR & (1<<22)) //如果發生fifo錯誤,亮紅色指示燈
{
MyDebugger_LEDs( red, on);
DMA1->LIFCR |= (1<<22);
}
}
實用程序:
頭文件:MyDebugger.h
// file:MyDebugger.h
#ifndef __MyDebugger_H #define __MyDebugger_H #include <stm32f4xx.h> #include <stdbool.h> /******LED宏定義*******/ #define green 0x00001000 #define orange 0x00002000 #define red 0x00004000 #define blue 0x00008000 /******全局變量及類型聲明*******/ enum LED_State {on, off, turn}; /******函數聲明*******/ void MyDebugger_Init(void); bool MyDebugger_Message(char *str_address, unsigned int str_len); void MyDebugger_LEDs(uint32_t LED, enum LED_State state); #endif源文件:MyDebugger.c
// file:MyDebugger.c #include <MyDebugger.h> #ifdef MyDebug_with_USART3 bool USART_DMA_Completed = true; /**************************************** 函數名:USART3_DMA_config 參數:無 返回值:無 功能:DMA1數據流3與usart3關聯的相關配置 ****************************************/ void USART3_DMA_config(void) { RCC->AHB1ENR |= (1<<21); //使能DMA1時鐘 DMA1_Stream3->CR &= 0xFFFFFFFE; //除能DMA1_Stream3 while(DMA1_Stream3->CR & 0x00000001);//確保DMA可以被設置 DMA1->LIFCR |= 0x0f800000;//傳送前清空DMA1_Stream3所有中斷標誌 DMA1_Stream3->PAR = (uint32_t)&USART3->DR;//設置外設地址USART3->DR地址0x40004804 //設置內存地址 DMA1_Stream3->FCR &= 0x00000000; DMA1_Stream3->FCR |= (1<<7);//設置fifo /* 設置dma通道4,即usart3tx 優先級最高 傳輸方向內存到外設 內存遞增模式 傳輸完成中斷使能 */ DMA1_Stream3->CR |= (0x08000000 | 0x00030000 | (1<<6) | (1<<10) | (1<<4)); NVIC->IP[14] = 0xA0; NVIC->ISER[0] |= (1<<14); } /************************** 函數名:USART3_config 參數:無 返回值:無 功能:配置usart3 ************************/ void USART3_config(void) { RCC->APB1ENR |= (1<<18); //使能usart3時鐘 RCC->AHB1ENR |= 0x00000008; //使能GPIOD時鐘 USART3->BRR = 0x0000016C; //波特率115200 /* 使能usart3 usart3發送使能 8bit 一位停止位 無校驗 */ USART3->CR1 |= ( ( 1<<13 ) | ( 1<<3 ) ); GPIOD->AFR[1] |= 0x00000077;//選擇PD8,9複用功能 GPIOD->MODER &= 0xFFF0FFFF; //設置PD8,9,複用模式 GPIOD->MODER |= 0x000A0000; // GPIOD->OTYPER &= 0xFFFFDFFF; //設置PD9推輓輸出 GPIOD->OSPEEDR &= 0xFFFCFFFF; //PD8速度50m GPIOD->OSPEEDR |= 0x00020000; GPIOD->PUPDR &= 0xFFFCFFFF; //PD8 GPIOD->PUPDR |= 0x00010000; } void DMA1_Stream3_IRQHandler(void) { if(DMA1->LISR & 0x08000000)//DMA傳輸完成 { USART_DMA_Completed = 1; DMA1->LIFCR |= 0x08000000;//清除中斷標誌 } } #endif /********************************************* 函數名:MyDebugger_Message 參數:char *str_address :要發送的字符串地址 unsigned int str_len :字符串的長度 返回值:bool 是否操作成功 功能:通過USART3發送信息 **********************************************/ bool MyDebugger_Message(char *str_address, unsigned int str_len) { #ifdef MyDebug_with_USB bool USB_Actioned; #endif #ifdef MyDebug_with_USART3 bool USART3_Actioned; if( USART_DMA_Completed ) //之前數據已經發送完成 { DMA1_Stream3->CR &= 0xFFFFFFFE; //除能DMA1_Stream3 while(DMA1_Stream3->CR & 0x00000001); //確保DMA可以被設置 DMA1->LIFCR |= 0x0f800000; //傳送前清空DMA1_Stream3所有中斷標誌 DMA1_Stream3->M0AR = (uint32_t)str_address; //設置內存地址 if((USART3->SR & (1<<7))) //發送數據寄存器空 { USART3->CR3 &= ~(1<<7);//usart3 dma發送模式除能 USART_DMA_Completed = 0; DMA1_Stream3->NDTR = str_len; //設置dma傳輸數據的數量 DMA1_Stream3->CR |= 1;//使能dma USART3->CR3 |= (1<<7);//usart3 dma發送模式使能 USART3_Actioned = 1; } } #endif #ifdef MyDebug_with_USB //以後或許實現用USB發送調試信息的代碼 //如果操作USB成功 USB_Actioned = 1; #endif #ifdef MyDebug_with_USART3 #ifndef MyDebug_with_USB return USART3_Actioned; #endif #endif #ifdef MyDebug_with_USB #ifndef MyDebug_with_USART3 return USB_Actioned; #endif #endif #ifdef MyDebug_with_USART3 #ifdef MyDebug_with_USB return (USART3_Actioned | USB_Actioned); #endif #endif } /**************************************** 函數名:LEDs_Init 參數:無 返回值:無 功能:初始化板子上的LED ****************************************/ void LEDs_Init(void) { RCC->AHB1ENR |= 0x00000008; //使能GPIOD時鐘 GPIOD->MODER &= 0x00FFFFFF; //設置PD12,13,14,15輸出 GPIOD->MODER |= 0x55000000; GPIOD->OTYPER &= 0xFFFF0FFF; //設置PD12,13,14,15推輓輸出 GPIOD->OSPEEDR &= 0x00FFFFFF; //PD12,13,14,15 速度100m GPIOD->PUPDR &= 0x00FFFFFF; //PD12,13,14,15 無上拉無下拉 GPIOD->BSRRH = 0xf000; //reset register GPIOx_BSRRH, write only //set register GPIOx_BSRRL, write only } /**************************************** 函數名:MyDebugger_LEDs 參數:uint32_t LED :要操作哪些LED enum LED_State state :作何操作 返回值:無 功能:改變LED的狀態 ****************************************/ void MyDebugger_LEDs(uint32_t LED, enum LED_State state) { uint32_t tmp; switch (state) { case on: { GPIOD->BSRRL |= LED; break; } case off: { GPIOD->BSRRH |= LED; break; } case turn: { tmp = (~GPIOD->ODR) & LED; GPIOD->ODR &= ~LED; GPIOD->ODR |= tmp; break; } } } /********************************************* 函數名:MyDebugger_Init 參數:無 返回值:無 功能:初始化MyDebugger **********************************************/ void MyDebugger_Init(void) { LEDs_Init(); #ifdef MyDebug_with_USART3 USART3_DMA_config(); USART3_config(); #endif }
主程序文件:main.c
/*********************************************
標題:MyDebugger
軟件平臺:IAR for ARM6.21
硬件平臺:stm32f4-discovery
主頻:168M
描述:實現一個調試工具
author:小船
data:2012-02-04
**********************************************/
#include <stm32f4xx.h>
#include <MyDebugger.h>
uint32_t Gb_TimingDelay;
void Delay(uint32_t nTime);
void main ()
{
SysTick_Config(SystemCoreClock / 1000); //設置systemtick一毫秒中斷
//char test[15] = {0, 1, 2, 3, 4, 10, 11, 12, 13, 14, 15, 0xfe, 0xf0, 0x07, 0x09};
SCB->AIRCR = 0x05AF0000 | 0x400; //中斷優先級分組 搶佔:響應=3:1
MyDebugger_Init();
while(1)
{
MyDebugger_Message("My name is Xian Yongwen\n\r",
sizeof("My name is Xian Yongwen\n\r")/sizeof(char));
MyDebugger_LEDs(blue, on);
Delay(500);
MyDebugger_Message("廣東石油化工學院\n\r",
sizeof("廣東石油化工學院\n\r")/sizeof(char));
MyDebugger_LEDs(blue, off);
Delay(500);
}
}
void Delay(uint32_t nTime)
{
Gb_TimingDelay = nTime;
while(Gb_TimingDelay != 0);
}
void SysTick_Handler(void)
{
if (Gb_TimingDelay != 0x00)
{
Gb_TimingDelay--;
}
}
運行結果: