知識點1【TRGO的介紹】
1、TRGO的概述
TRGO:Trigger Output(觸發輸出),是定時器的一種功能。
它可以作為外設的啟動信號,比如ADC轉換,DAC輸出,DMA請求等。
對于ADC來說,可以通過TRGO信號來觸發ADC開始轉換
2、定時器TRGO的生成過程
以通用定時器為例,TRGO信號的來源可以是:更新事件,比較事件,其他事件。如下圖
通過TIM_SelectOutputTrigger()
進行配置
3、補充
(1)ADC持續轉換的兩種方式
1、ContinuousConvMode = ENABLE
+ ExternalTrig = None
啟動連續采集,適合實時采樣
2、ContinuousConvMode = DISABLE
+ ExternalTrig = TIMx_TRGO
每次觸發采樣一次,適合周期性定點采樣
每次定時器觸發都會掃描一次所有通道
(2)DMA—TC中斷的觸發時機
當ADC完成一次完整的通道掃描,并且DMA將所有通道的結果都搬運到內存后,才會觸發DMA傳輸完成中斷(TC)
知識點2【代碼練習】
本代碼是一個將ADC(多通道),DMA(中斷),TIM(TRGO)相結合的案例
實現的功能是ADC每秒轉換一次,但這里我只有一個光敏元件,因此只有一個通道有數據。
main.c
#include "stm32f10x.h"
#include "stm32f10x_conf.h"
#include "delay.h"
#include "usart.h"
#include "adc.h"
#include "dma.h"
#include "tim.h"
u16 ADC3_Recv_Data;
int flag;#define ADC_NUM 3//ADC + DAM(中斷) + TRGO
//多通道接收數據 用數組保存
u16 data_adc_mult[ADC_NUM] = {0};//需要配置的有
//ADC3 IN6 IN5 IN4:PF8 PF7 PF6 ok
//USART1 TX:PA9,RX:PA10 ok
//DMA2 CH5
//TIM3 TRGO okint main(void)
{//中斷向量組配置Systick_Init(72000);NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);Usart1_Init(9600);ADC3_Interrupt_DMA_TIM_GPIO_Init();ADC3_Interrupt_DMA_TIM_Init();DMA2_IN5_ADC3_Init();TIM3_TRGO_Init();while(1){ }
}
adc.c
#include "adc.h"
#define ADC_NUM 3void ADC3_Interrupt_DMA_TIM_Init(void)
{ADC_InitTypeDef ADC3_InitStruct;//時鐘 分頻RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC3,ENABLE);RCC_ADCCLKConfig(RCC_PCLK2_Div6);//ADC3初始化 配置為外部觸發ADC_StructInit(&ADC3_InitStruct); ADC3_InitStruct.ADC_ContinuousConvMode = DISABLE;ADC3_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;ADC3_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T3_TRGO;ADC3_InitStruct.ADC_Mode = ADC_Mode_Independent;ADC3_InitStruct.ADC_NbrOfChannel = ADC_NUM;ADC3_InitStruct.ADC_ScanConvMode = ENABLE;ADC_Init(ADC3,&ADC3_InitStruct);//通道配置ADC_RegularChannelConfig(ADC3,ADC_Channel_6,1,ADC_SampleTime_55Cycles5);ADC_RegularChannelConfig(ADC3,ADC_Channel_5,2,ADC_SampleTime_55Cycles5);ADC_RegularChannelConfig(ADC3,ADC_Channel_4,3,ADC_SampleTime_55Cycles5);//使能ADC3 + DAMADC_Cmd(ADC3,ENABLE);ADC_DMACmd(ADC3,ENABLE);ADC_ExternalTrigConvCmd(ADC3, ENABLE);//外部觸發//校驗ADC_ResetCalibration(ADC3);while(ADC_GetResetCalibrationStatus(ADC3) == SET);ADC_StartCalibration(ADC3);while(ADC_GetCalibrationStatus(ADC3) == SET);//開始轉換//ADC_SoftwareStartConvCmd(ADC3,ENABLE);//由于是外部觸發 因此這句話不需要寫
}void ADC3_Interrupt_DMA_TIM_GPIO_Init(void)
{GPIO_InitTypeDef GPIOF_InitStruct;//時鐘RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOF,ENABLE);//配置PF8 PF7 PF6為模擬輸入GPIO_StructInit(&GPIOF_InitStruct);GPIOF_InitStruct.GPIO_Mode = GPIO_Mode_AIN;GPIOF_InitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8;GPIOF_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOF,&GPIOF_InitStruct);
}
dma.c
#include "dma.h"
extern u16 data_adc_mult[ADC_NUM];void DMA2_IN5_ADC3_Init(void)
{DMA_InitTypeDef DMA2_InitStruct;NVIC_InitTypeDef NVIC_InitStruct;//時鐘配置RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2,ENABLE);//初始化DMA2_InitStruct.DMA_BufferSize = ADC_NUM;DMA2_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC;DMA2_InitStruct.DMA_M2M = DMA_M2M_Disable;DMA2_InitStruct.DMA_MemoryBaseAddr = (u32)data_adc_mult;DMA2_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //ADC數據12位DMA2_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;DMA2_InitStruct.DMA_Mode = DMA_Mode_Circular;//這里需要設置循環模式的原因://每次觸發都需要 重新將DMA的計數器復位DMA2_InitStruct.DMA_PeripheralBaseAddr = (u32)&ADC3->DR;DMA2_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;DMA2_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;DMA2_InitStruct.DMA_Priority = DMA_Priority_High;DMA_Init(DMA2_Channel5,&DMA2_InitStruct);//中斷使能DMA_ITConfig(DMA2_Channel5,DMA_IT_TC,ENABLE);NVIC_InitStruct.NVIC_IRQChannel = DMA2_Channel4_5_IRQn;NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;NVIC_Init(&NVIC_InitStruct);//使能DMADMA_Cmd(DMA2_Channel5,ENABLE);
}//中斷處理函數
void DMA2_Channel4_5_IRQHandler(void)
{if(DMA_GetITStatus(DMA2_IT_TC5) == SET){int i = 0;DMA_ClearITPendingBit(DMA2_IT_TC5);for(i = 0;i < ADC_NUM ;i++){printf("%f ",DataProcess_light(data_adc_mult[i]));}printf("\\n");}
}
tim.c
**#include "tim.h"
void TIM3_TRGO_Init(void)
{TIM_TimeBaseInitTypeDef TIM3_InitStrct;//時鐘RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//定時器初始化TIM_TimeBaseStructInit(&TIM3_InitStrct);TIM3_InitStrct.TIM_ClockDivision = TIM_CKD_DIV1;TIM3_InitStrct.TIM_CounterMode = TIM_CounterMode_Up;TIM3_InitStrct.TIM_Period = 10000 - 1;TIM3_InitStrct.TIM_Prescaler = 7200 - 1;TIM_TimeBaseInit(TIM3,&TIM3_InitStrct);//開啟外部觸發TIM_SelectOutputTrigger(TIM3,TIM_TRGOSource_Update);//使能定時器TIM_Cmd(TIM3,ENABLE);
}**
usart.c
#include "usart.h"
#include "led.h"//串口2初始化
void Usart2_Init(u32 Baud)
{GPIO_InitTypeDef GPIOA_Pin2_InitStruct;GPIO_InitTypeDef GPIOA_Pin3_InitStruct;USART_InitTypeDef USART2_InitStruct;//時鐘配置 USART,收(PA3)發(PA2)端口 RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);GPIO_StructInit(&GPIOA_Pin3_InitStruct);GPIOA_Pin3_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIOA_Pin3_InitStruct.GPIO_Pin = GPIO_Pin_3;GPIOA_Pin3_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;//收PA3端口配置GPIO_Init(GPIOA,&GPIOA_Pin3_InitStruct);GPIO_StructInit(&GPIOA_Pin2_InitStruct);GPIOA_Pin2_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;GPIOA_Pin2_InitStruct.GPIO_Pin = GPIO_Pin_2;GPIOA_Pin2_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;//發PA2端口配置GPIO_Init(GPIOA,&GPIOA_Pin2_InitStruct);//串口初始化USART2_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;USART2_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;USART2_InitStruct.USART_BaudRate = Baud;USART2_InitStruct.USART_Parity = USART_Parity_No;USART2_InitStruct.USART_StopBits = USART_StopBits_1;USART2_InitStruct.USART_WordLength = USART_WordLength_8b;USART_Init(USART2,&USART2_InitStruct);//使能串口USART_Cmd(USART2,ENABLE);
}//串口1初始化
void Usart1_Init(u32 Baud)
{GPIO_InitTypeDef GPIOB_InitStruct;USART_InitTypeDef USART1_InitStruct;//時鐘配置 USART1,TX:PA9,RX:PA10RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//端口配置GPIOB_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;GPIOB_InitStruct.GPIO_Pin = GPIO_Pin_9;GPIOB_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIOB_InitStruct);GPIOB_InitStruct.GPIO_Pin = GPIO_Pin_10;GPIOB_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_Init(GPIOA,&GPIOB_InitStruct);//串口初始化USART1_InitStruct.USART_BaudRate = Baud;USART1_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;USART1_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;USART1_InitStruct.USART_Parity = USART_Parity_No;USART1_InitStruct.USART_StopBits = USART_StopBits_1;USART1_InitStruct.USART_WordLength = USART_WordLength_8b;USART_Init(USART1,&USART1_InitStruct);//使能串口USART_Cmd(USART1,ENABLE);
}//串口1發送數據函數發送數據
void USART1_Trans(u8 c)
{while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);USART_SendData(USART1,c);while(USART_GetFlagStatus(USART1,USART_FLAG_TC) == RESET);
}int fputc(int c,FILE *stream)
{USART1_Trans((u8)c);return c;
}
delay.c
#include "delay.h"u32 delay_ms = 0;//系統定時器初始化函數
void Systick_Init(u32 ticks)
{SysTick_Config(ticks);
}//延時函數
void Delay_ms(u32 ms)
{u32 ticks = delay_ms + ms;while(ticks > delay_ms);
}//系統定時器中斷服務函數
void SysTick_Handler(void)
{delay_ms++;
}
錯誤
1、DMA_BufferSize理解錯誤
2、DMA_Mode_Circular未配置循環模式
3、ADC_ExternalTrigConvCmd(ADC3, ENABLE);
未開啟ADC3的外部觸發轉換
?
結束
代碼重在練習!
代碼重在練習!
代碼重在練習!
今天的分享就到此結束了,希望對你有所幫助,如果你喜歡我的分享,請點贊收藏加關注,謝謝大家!!!