资讯详情

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

对于规则通道组,每个通道在间歇模式下转换,EOC位置一次。所以不需要像。SCAN必须采用这种模式DMA处理数据。

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

在以下程序中,DISCNUM=每次转换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设为模拟, PA待机唤醒按钮设置为带下拉电阻输入  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.打开间歇模式。,否则第一次转换就会出错!

【程序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设为模拟, PA待机唤醒按钮设置为带下拉电阻输入  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-&g;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=0x%02x)\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)模式不能和间断模式同时使用。

标签: 电阻1776

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台