STM32F103RC单片机ADC中的间断模式(Discontinous mode)的使用

xiaoxiao2021-02-28  92

对于规则通道组,间断模式下每转换一个通道,EOC就会置位一次。因此不必像SCAN模式那样必须采用DMA来搬运数据。

当DISCEN=1时打开间断模式,DISCNUM指定每次转换的通道个数,范围为1~8。

在下面的程序中,DISCNUM=011,每次转换4个通道。L=1001,总共有10个通道。

【程序1】

#include <stdio.h> #include <stm32f10x.h> void delay(void) { uint32_t i; for (i = 0; i < 2000000; i++); } int fputc(int ch, FILE *fp) { if (fp == stdout) { if (ch == '\n') { while ((USART1->SR & USART_SR_TXE) == 0); USART1->DR = '\r'; } while ((USART1->SR & USART_SR_TXE) == 0); USART1->DR = ch; } return ch; } void convert(void) { uint8_t i, j, n; uint16_t result[4]; for (i = 0; i < 10; i += n) { ADC1->CR2 |= ADC_CR2_SWSTART; n = (i + 4 > 10) ? 10 - i : 4; for (j = 0; j < n; j++) { while ((ADC1->SR & ADC_SR_EOC) == 0); result[j] = ADC1->DR; } printf("[Regular SQ%d~%d]", i + 1, i + n); for (j = 0; j < n; j++) printf(" %d", result[j]); printf("\n"); } } int main(void) { uint8_t i = 3; // 打开外设时钟 RCC->CFGR |= RCC_CFGR_ADCPRE_1; // ADC时钟设为12MHz, 最大允许时钟为14MHz RCC->APB1ENR = RCC_APB1ENR_PWREN; RCC->APB2ENR = RCC_APB2ENR_ADC1EN | RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_USART1EN; GPIOA->CRH = 0x444444b4; // 串口发送端设为复用推挽50MHz输出 GPIOA->CRL = 0x00000008; // ADC1通道1~7设为模拟, PA0待机唤醒按键设为带下拉电阻输入 GPIOB->CRL = 0x44444400; // ADC1通道8~9设为模拟 // 规则通道序列 ADC1->SQR1 = ADC_SQR1_L_3 | ADC_SQR1_L_0; // 10个通道 ADC1->SQR2 = ADC_SQR2_SQ10_4 | (ADC_SQR2_SQ9_3 | ADC_SQR2_SQ9_0) | ADC_SQR2_SQ8_3 | (ADC_SQR2_SQ7_2 | ADC_SQR2_SQ7_1 | ADC_SQR2_SQ7_0); ADC1->SQR3 = (ADC_SQR3_SQ6_2 | ADC_SQR3_SQ6_1) | (ADC_SQR3_SQ5_2 | ADC_SQR3_SQ5_0) | ADC_SQR3_SQ4_2 | (ADC_SQR3_SQ3_1 | ADC_SQR3_SQ3_0) | ADC_SQR3_SQ2_1 | ADC_SQR3_SQ1_0; ADC1->CR1 = ADC_CR1_DISCEN | ADC_CR1_DISCNUM_1 | ADC_CR1_DISCNUM_0; // 每次转换的规则通道数为4 ADC1->CR2 = ADC_CR2_TSVREFE | ADC_CR2_EXTTRIG | ADC_CR2_EXTSEL | ADC_CR2_ADON; // 打开ADC1, 规则通道设为外部触发模式 USART1->BRR = 0x271; // 波特率: 115200 USART1->CR1 = USART_CR1_UE | USART_CR1_TE; // 允许发送 while (i--) convert(); ADC1->SR &= ~ADC_SR_STRT; printf("ADC1->SR=0xx\n", ADC1->SR); // 进入待机模式 while ((USART1->SR & USART_SR_TC) == 0); // 等待USART1发送完毕 while (GPIOA->IDR & GPIO_IDR_IDR0) delay(); // WKUP按键消抖 SCB->SCR = SCB_SCR_SLEEPDEEP; PWR->CR = PWR_CR_PDDS | PWR_CR_CWUF; PWR->CSR = PWR_CSR_EWUP; __WFI(); return 0; }【运行结果】 [Regular SQ1~4] 302 724 1014 1356 [Regular SQ5~8] 1774 2493 2870 3177 [Regular SQ9~10] 3687 2100 [Regular SQ1~4] 303 724 1014 1356 [Regular SQ5~8] 1776 2493 2867 3177 [Regular SQ9~10] 3689 2100 [Regular SQ1~4] 302 723 1015 1354 [Regular SQ5~8] 1774 2492 2869 3176 [Regular SQ9~10] 3687 2100 ADC1->SR=0x00由运行结果可知,如果通道组中剩余的通道数大于或等于4个通道,则转换4个通道,否则剩下几个就转换几个。

对于注入通道组,则是每次触发只转换一个通道,DISCNUM的值无效。当整个通道组转换完毕时EOC和JEOC同时置1。

当JDISCEN=1时打开间断模式。注意SCAN必须置1,否则第一次转换时将会出错!

【程序2】

#include <stdio.h> #include <stm32f10x.h> int fputc(int ch, FILE *fp) { if (fp == stdout) { if (ch == '\n') { while ((USART1->SR & USART_SR_TXE) == 0); USART1->DR = '\r'; } while ((USART1->SR & USART_SR_TXE) == 0); USART1->DR = ch; } return ch; } int main(void) { uint8_t i = 0; // 打开外设时钟 RCC->CFGR |= RCC_CFGR_ADCPRE_1; // ADC时钟设为12MHz, 最大允许时钟为14MHz RCC->APB1ENR = RCC_APB1ENR_TIM2EN; RCC->APB2ENR = RCC_APB2ENR_ADC1EN | RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_USART1EN; GPIOA->CRH = 0x444444b4; // 串口发送端设为复用推挽50MHz输出 GPIOA->CRL = 0x00000008; // ADC1通道1~7设为模拟, PA0待机唤醒按键设为带下拉电阻输入 GPIOB->CRL = 0x44444400; // ADC1通道8~9设为模拟 USART1->BRR = 0x271; // 波特率: 115200 USART1->CR1 = USART_CR1_UE | USART_CR1_TE; // 允许发送 printf("-------------------------------------------------------\n"); TIM2->ARR = 3332; TIM2->PSC = 7199; TIM2->CR1 = TIM_CR1_URS; TIM2->CR2 = TIM_CR2_MMS_1; // TRGO=UIF TIM2->DIER = TIM_DIER_UIE; TIM2->EGR = TIM_EGR_UG; // JEXTTRIG必须为0, 否则将触发转换 NVIC_EnableIRQ(TIM2_IRQn); ADC1->JSQR = ADC_JSQR_JL_1 | ADC_JSQR_JSQ4_2 | (ADC_JSQR_JSQ3_1 | ADC_JSQR_JSQ3_0) | ADC_JSQR_JSQ2_1; // 注入通道序列 ADC1->CR1 = ADC_CR1_SCAN | ADC_CR1_JDISCEN; // 一定要同时把SCAN模式打开!!!否则当EOC第一次置位时只转换了一个通道 ADC1->CR2 = ADC_CR2_JEXTTRIG | ADC_CR2_JEXTSEL_1 | ADC_CR2_ADON; // 打开ADC1, 注入通道设为TIM2_TRGO触发 TIM2->CR1 |= TIM_CR1_CEN; while (1) { while ((ADC1->SR & ADC_SR_JEOC) == 0); ADC1->SR &= ~(ADC_SR_JSTRT | ADC_SR_EOC | ADC_SR_JEOC); printf(" %d %d %d %d (ADC1->SR=0xx)\n", ADC1->JDR1, ADC1->JDR2, ADC1->JDR3, ADC1->JDR4, ADC1->SR); if (i == 4) ADC1->JSQR |= ADC_JSQR_JL_0 | ADC_JSQR_JSQ1_0; // 增加一个通道 if (i != 5) i++; } } void TIM2_IRQHandler(void) { TIM2->SR &= ~TIM_SR_UIF; printf("*"); }【运行结果】 ------------------------------------------------------- *** 725 1015 1358 0 (ADC1->SR=0x00) *** 723 1014 1357 0 (ADC1->SR=0x00) *** 725 1015 1357 0 (ADC1->SR=0x00) *** 724 1015 1357 0 (ADC1->SR=0x00) *** 724 1015 1357 0 (ADC1->SR=0x00) **** 303 724 1014 1357 (ADC1->SR=0x00) **** 303 727 1016 1357 (ADC1->SR=0x00) **** 303 724 1015 1358 (ADC1->SR=0x00) **** 303 724 1015 1358 (ADC1->SR=0x00) **** 303 725 1015 1357 (ADC1->SR=0x00) **** 303 724 1014 1357 (ADC1->SR=0x00) **** 304 725 1015 1359 (ADC1->SR=0x00) **** 303 725 1015 1356 (ADC1->SR=0x00) **** 303 724 1015 1357 (ADC1->SR=0x00) **** 304 723 1015 1357 (ADC1->SR=0x00) **** 305 726 1015 1357 (ADC1->SR=0x00) **** 303 725 1016 1357 (ADC1->SR=0x00) **** 303 725 1015 1357 (ADC1->SR=0x00) **** 304 725 1015 1358 (ADC1->SR=0x00) **** 303 723 1015 1357 (ADC1->SR=0x00) **** 303 724 1014 1357 (ADC1->SR=0x00) **** 303 724 1015 1357 (ADC1->SR=0x00) **** 304 724 1015 1357 (ADC1->SR=0x00) **** 302 725 1014 1357 (ADC1->SR=0x00) **** 303 724 1014 1357 (ADC1->SR=0x00) **** 302 724 1015 1357 (ADC1->SR=0x00)

如果忘记将SCAN置1,则第一排只有一个星号,也就是只触发了一次就完成了一组单通道转换,但后续的转换没有问题。

ADC1->CR1 = /*ADC_CR1_SCAN | */ADC_CR1_JDISCEN; ------------------------------------------------------- * 724 0 0 0 (ADC1->SR=0x00) *** 725 1015 1358 0 (ADC1->SR=0x00) *** 725 1015 1358 0 (ADC1->SR=0x00) *** 724 1015 1358 0 (ADC1->SR=0x00) *** 725 1014 1357 0 (ADC1->SR=0x00) **** 304 723 1016 1357 (ADC1->SR=0x00) **** 303 725 1015 1357 (ADC1->SR=0x00)

【程序2(库函数版)】

#include <stdio.h> #include <stm32f10x.h> int fputc(int ch, FILE *fp) { if (fp == stdout) { if (ch == '\n') { while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); USART_SendData(USART1, '\r'); } while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); USART_SendData(USART1, ch); } return ch; } int main(void) { ADC_InitTypeDef adc; GPIO_InitTypeDef gpio; TIM_TimeBaseInitTypeDef tim; USART_InitTypeDef usart; uint8_t i = 0; RCC_ADCCLKConfig(RCC_PCLK2_Div6); RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_USART1, ENABLE); gpio.GPIO_Mode = GPIO_Mode_AF_PP; gpio.GPIO_Pin = GPIO_Pin_9; gpio.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &gpio); gpio.GPIO_Mode = GPIO_Mode_AIN; gpio.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7; GPIO_Init(GPIOA, &gpio); gpio.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1; GPIO_Init(GPIOB, &gpio); USART_StructInit(&usart); usart.USART_BaudRate = 115200; usart.USART_Mode = USART_Mode_Tx; USART_Init(USART1, &usart); USART_Cmd(USART1, ENABLE); printf("-------------------------------------------------------\n"); TIM_UpdateRequestConfig(TIM2, TIM_UpdateSource_Regular); // URS=1, 防止TIM_TimeBaseInit产生中断 TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update); TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); NVIC_EnableIRQ(TIM2_IRQn); TIM_TimeBaseStructInit(&tim); tim.TIM_Period = 3332; tim.TIM_Prescaler = 7199; TIM_TimeBaseInit(TIM2, &tim); ADC_StructInit(&adc); adc.ADC_ScanConvMode = ENABLE; ADC_Init(ADC1, &adc); ADC_InjectedDiscModeCmd(ADC1, ENABLE); ADC_ExternalTrigInjectedConvConfig(ADC1, ADC_ExternalTrigInjecConv_T2_TRGO); ADC_ExternalTrigInjectedConvCmd(ADC1, ENABLE); ADC_InjectedSequencerLengthConfig(ADC1, 3); // 必须先设置通道数JL ADC_InjectedChannelConfig(ADC1, ADC_Channel_2, 1, ADC_SampleTime_1Cycles5); // Rank从1开始, 对应的是JSQR寄存器中的JSQ2 ADC_InjectedChannelConfig(ADC1, ADC_Channel_3, 2, ADC_SampleTime_1Cycles5); // JSQ3 ADC_InjectedChannelConfig(ADC1, ADC_Channel_4, 3, ADC_SampleTime_1Cycles5); // JSQ4 ADC_Cmd(ADC1, ENABLE); TIM_Cmd(TIM2, ENABLE); while (1) { while (ADC_GetFlagStatus(ADC1, ADC_FLAG_JEOC) == RESET); ADC_ClearFlag(ADC1, ADC_FLAG_JSTRT | ADC_FLAG_EOC | ADC_FLAG_JEOC); printf(" %d %d %d %d (ADC1->SR=0xx)\n", ADC_GetInjectedConversionValue(ADC1, ADC_InjectedChannel_1), ADC_GetInjectedConversionValue(ADC1, ADC_InjectedChannel_2), ADC_GetInjectedConversionValue(ADC1, ADC_InjectedChannel_3), ADC_GetInjectedConversionValue(ADC1, ADC_InjectedChannel_4), ADC1->SR); if (i == 4) { ADC_InjectedSequencerLengthConfig(ADC1, 4); ADC_InjectedChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_1Cycles5); } if (i != 5) i++; } } void TIM2_IRQHandler(void) { TIM_ClearITPendingBit(TIM2, TIM_IT_Update); printf("*"); }

【注意】

1. 规则通道组和注入通道组不能同时打开间断模式。

2. 自动注入(JAUTO)模式不能和间断模式同时使用。

转载请注明原文地址: https://www.6miu.com/read-56499.html

最新回复(0)