你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32基础设计---ADC转换(中断方式)

[复制链接]
STMCU小助手 发布时间:2023-1-4 21:03
通过中断方式读取电压,不过最后楼主读取参考电压失败,还没有找到错误,所以读取的电压只能十六进制显示,

本文的介绍按照一般流程来走:
1,串口的初始化
2,ADC初始化
3,中断初始化
4,编写中断函数
5,编写主函数

接下来详细介绍:

1,串口的初始化:
  1. void usart_init()
  2. {
  3.          GPIO_InitTypeDef Uart_A;  
  4.       
  5.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA ,ENABLE);  
  6.     Uart_A.GPIO_Pin = GPIO_Pin_9;  
  7.     Uart_A.GPIO_Speed = GPIO_Speed_50MHz;  
  8.     Uart_A.GPIO_Mode = GPIO_Mode_AF_PP;  
  9.     GPIO_Init(GPIOA,&Uart_A);  
  10.       
  11.     Uart_A.GPIO_Pin = GPIO_Pin_10;  
  12.     Uart_A.GPIO_Speed = GPIO_Speed_50MHz;  
  13.     Uart_A.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  14.     GPIO_Init(GPIOA,&Uart_A);   
  15.        
  16.         USART_InitTypeDef Uart;  
  17.       
  18.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);  
  19.     Uart.USART_BaudRate = 115200;  
  20.     Uart.USART_HardwareFlowControl = USART_HardwareFlowControl_None;  
  21.     Uart.USART_Mode = USART_Mode_Tx;  
  22.     Uart.USART_Parity = USART_Parity_No;  
  23.     Uart.USART_StopBits = USART_StopBits_1;  
  24.     Uart.USART_WordLength = USART_WordLength_8b;  
  25.     USART_Init(USART1,&Uart);  
  26.       
  27.     USART_Cmd(USART1,ENABLE);  
  28.     USART_ClearFlag(USART1,USART_FLAG_TC);
  29. }
复制代码


关于本段代码,我前面写的文章STM32基础设计(3)有详细讲解,此处不再赘述。


2,ADC初始化
  1. typedef struct
  2. {//配置ADC的模式,一个ADC是独立模式,2个是双模式
  3.   uint32_t ADC_Mode;                      /*!< Configures the ADC to operate in independent or
  4.                                                dual mode.
  5.                                                This parameter can be a value of @ref ADC_mode */
  6. //配置ADC是否使用扫描,单通道不扫描,多通道扫描
  7.   FunctionalState ADC_ScanConvMode;       /*!< Specifies whether the conversion is performed in
  8.                                                Scan (multichannels) or Single (one channel) mode.
  9.                                                This parameter can be set to ENABLE or DISABLE */
  10. //配置ADC是单次转换还是连续转换
  11.   FunctionalState ADC_ContinuousConvMode; /*!< Specifies whether the conversion is performed in
  12.                                                Continuous or Single mode.
  13.                                                This parameter can be set to ENABLE or DISABLE. */
  14. //外部触发选择
  15.   uint32_t ADC_ExternalTrigConv;          /*!< Defines the external trigger used to start the analog
  16.                                                to digital conversion of regular channels. This parameter
  17.                                                can be a value of @ref ADC_external_trigger_sources_for_regular_channels_conversion */
  18. //转换结果数据对其方式
  19.   uint32_t ADC_DataAlign;                 /*!< Specifies whether the ADC data alignment is left or right.
  20.                                                This parameter can be a value of @ref ADC_data_align */
  21. //ADC转换的通道数目
  22.   uint8_t ADC_NbrOfChannel;               /*!< Specifies the number of ADC channels that will be converted
  23.                                                using the sequencer for regular channel group.
  24.                                                This parameter must range from 1 to 16. */
  25. }ADC_InitTypeDef;
复制代码


下面粘贴代码:

  1. void Adc_Init()
  2. {
  3.         ADC_InitTypeDef adc;//定义ADC结构的变量
  4.         GPIO_InitTypeDef io_b;//定义串口结构体变量 ,开发板上的电源接的是GPIOB端口的 1引脚,查数据手册,其为ADC1的9通道
  5.        
  6.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOB,ENABLE);//开时钟(即把心脏激活)
  7.         RCC_ADCCLKConfig(RCC_PCLK2_Div6);
  8.        
  9.         io_b.GPIO_Pin = GPIO_Pin_1;//设置端口引脚为 引脚1
  10.         io_b.GPIO_Mode = GPIO_Mode_AIN;//设置为输入模式
  11.         io_b.GPIO_Speed = GPIO_Speed_50MHz;//最高速率为50MHz
  12.         GPIO_Init(GPIOB,&io_b);初始化引脚
  13.         ADC_DeInit(ADC1);先将外设ADC1的全部寄存器重设为默认值 ADC_TempSensorVrefintCmd(ENABLE);谁能外部参照电压(勿忘)
  14.         adc.ADC_Mode = ADC_Mode_Independent;设置ADC为独立模式
  15.         adc.ADC_ScanConvMode = ENABLE;使能扫描模式
  16.         adc.ADC_ContinuousConvMode = ENABLE;使能连续扫描
  17.         adc.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;不使用外部触发
  18.         adc.ADC_DataAlign = ADC_DataAlign_Right;数据右对齐
  19.         adc.ADC_NbrOfChannel = 2;来制定用几个ADC通达(勿忘)
  20.         ADC_Init(ADC1,&adc);初始化ADC寄存器
  21.        
  22.         ADC_RegularChannelConfig(ADC1,ADC_Channel_9,1,ADC_SampleTime_239Cycles5);制定用哪个ADC转换、第几个通道,转换的顺序、转换的周期
  23.         ADC_RegularChannelConfig(ADC1,ADC_Channel_17,2,ADC_SampleTime_239Cycles5);
  24.         //这里需要根据数据手册来设定通道,数据手册上会说明那个引脚对应那个通道,外接电源接到那个引脚上就可以了,必须按照数据手册的要求来,不然肯定会出错,博主在这里就有一个很大很大的教训,望读者谨记
  25.         ADC_ITConfig(ADC1,ADC_IT_EOC,ENABLE);打开ADC中断
  26.         ADC_Cmd(ADC1,ENABLE);使能ADC1
  27.         ADC_ResetCalibration(ADC1);复位ADC1的校准寄存器
  28.         while(ADC_GetResetCalibrationStatus(ADC1));等待校准寄存器复位完成
  29.        
  30.         ADC_StartCalibration(ADC1);开始ADC1校准
  31.         while(ADC_GetCalibrationStatus(ADC1));等待ADC1校准完成
  32.         ADC_SoftwareStartConvCmd(ADC1,ENABLE);使能指定的ADC1的软件转换启动功能
  33. }
复制代码

3.中断初始化
  1. void adc_nvic_init()
  2. {
  3.        
  4.         NVIC_InitTypeDef nvic;定义中断结构体
  5.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);设置中断分组
  6.         nvic.NVIC_IRQChannel = ADC1_2_IRQn;制定专断通道
  7.         nvic.NVIC_IRQChannelCmd = ENABLE;使能中断
  8.         nvic.NVIC_IRQChannelPreemptionPriority = 1;抢占优先级
  9.         nvic.NVIC_IRQChannelSubPriority = 1;子优先级
  10.         NVIC_Init(&nvic);初始化
  11.        
  12.         NVIC_InitTypeDef usart1;定义中断结构体
  13.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);设置中断分组
  14.         usart1.NVIC_IRQChannel = USART1_IRQn;指定中断通道
  15.         usart1.NVIC_IRQChannelCmd = ENABLE;设能中断通道
  16.         usart1.NVIC_IRQChannelPreemptionPriority = 0;抢占优先级
  17.         usart1.NVIC_IRQChannelSubPriority= 0;子优先级
  18.         NVIC_Init(&usart1);中断初始化
  19. }
复制代码


4,编写中断函数
先粘贴代码:
  1. void ADC1_2_IRQHandler()
  2. {
  3.         if(ADC_GetITStatus(ADC1,ADC_IT_EOC) == SET)这里使用来判断,如果已经转换完成EOC位为1,具体请查看参考手册ADC状态寄存器ADC_SR的eEOC位
  4.         {if(count_1%2 == 0){代码中的if语句中的嵌套if语句是用来区分外接电源电压和内部参考电压的。具体见下面的解释
  5.                 ADC_ConvertedValue = ADC_GetConversionValue(ADC1);
  6.                 count_1++;
  7.         }else
  8.                         {
  9.                                 ADC_ConvertedValue_1 = ADC_GetConversionValue(ADC1);
  10.                                 //ADC_ConvertedValue_1 = ADC1->DR;
  11.                                 count_1++;
  12.                         }
  13.         }
  14.         ADC_ClearITPendingBit(ADC1,ADC_IT_EOC);
  15. }

  16. void USART1_IRQHandler(void)
  17. {
  18.         if(USART_GetFlagStatus(USART1,USART_FLAG_TXE))判断是否可以发送数据
  19.         {
  20.                 USART1->CR1 &= ~USART_CR1_TXEIE;在这里笔者也碰到了问题,详见下文
  21.                 USART1->DR = car;
  22.                 while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);
  23.                 //USART1->CR1 &= ~USART_CR1_TXEIE;
  24.         }
  25.        
  26.         if(USART1->SR & USART_SR_RXNE)判断是否可以接收数据
  27.         {
  28.                 volatile int8_t com_data;
  29.                 com_data = USART1->DR;
  30.         }
  31. }
复制代码

在ADC中断服务函数中,代码中的if语句中的嵌套if语句是用来区分外接电源电压和内部参考电压的,因为第一次接受的是外部电源电压,第二次接受的是内部参考电压,所以可以利用奇偶数,即偶数用ADC_ConvertedValue来存放外部电源电压值,奇数时用ADC_ConvertedValue_1来存放参考电压值。但是,笔者发现,这样会失败,经过串口调试发现两次接受到的值都一样,笔者初步认为,可能是ADC的转换速率太快了,具体什么歌情况还不清楚,等下一个基础设计ADC转换(DMA方式)的时候在细究。

关于那个还要在中断服务函数中再次将TXEIE设置为零,是因为发送中断是通过 打开中断函数(USART_ITConfig)进入的,该函数中已经将CR1寄存器中的TXEIE位置1 的,所以中断服务函数中还要再次清0,以防止再中断。

---------------------------------------------------------------------------------------------------------------------------------

5,编写主函数

  1. int main()
  2. {
  3.         void PrintU16(uint16_t num);
  4.         void PrintHexU8(uint8_t data);

  5.         Adc_Init();
  6.         adc_nvic_init();
  7.         usart_init();
  8.         while(1)
  9.         {
  10.                 num = (uint16_t)(2.0f* ADC_ConvertedValue/ADC_ConvertedValue_1 *1.2f*100 );参考电压是1.2f通过比例关系算出实际电压。
  11.                 PrintU16(num);
  12.                 delay(1000);
  13.         }
  14. }
复制代码


笔者并没有计算出准确的电压值,只是采集到两个电压值,笔者猜测,可能是因为ADC的转换速率太快,导致笔者的  通过奇偶数来区分内部电压和外部电压不管用了,笔者还在思考解决方式,如果读者有好的方法,请指教


本文到此结束,下面是完整代码:

  1. #include<stm32f10x.h>
  2. #define uint unsigned int
  3. #define uchar unsigned char
  4.        
  5. char car;
  6. static char count_1=0;//当做奇偶数
  7. uint16_t ADC_ConvertedValue;//存放电源电压
  8. uint16_t ADC_ConvertedValue_1;//存放内部参照电压
  9.         static uint16_t num=0;
  10. void delay(uint n)
  11. {
  12.         int i,j;
  13.         for(i=0;i<n;i++)
  14.         for(j=0;j<8500;j++);
  15. }

  16. void Adc_Init()
  17. {
  18.         ADC_InitTypeDef adc;
  19.         GPIO_InitTypeDef io_b;
  20.        
  21.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOB,ENABLE);
  22.         RCC_ADCCLKConfig(RCC_PCLK2_Div6);
  23.        
  24.         io_b.GPIO_Pin = GPIO_Pin_1;
  25.         io_b.GPIO_Mode = GPIO_Mode_AIN;
  26.         io_b.GPIO_Speed = GPIO_Speed_50MHz;
  27.         GPIO_Init(GPIOB,&io_b);
  28.        
  29.         ADC_DeInit(ADC1);
  30.         ADC_TempSensorVrefintCmd(ENABLE);
  31.         adc.ADC_Mode = ADC_Mode_Independent;
  32.         adc.ADC_ScanConvMode = ENABLE;
  33.         adc.ADC_ContinuousConvMode = ENABLE;
  34.         adc.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
  35.         adc.ADC_DataAlign = ADC_DataAlign_Right;
  36.         adc.ADC_NbrOfChannel = 2;
  37.         ADC_Init(ADC1,&adc);
  38.        
  39.         ADC_RegularChannelConfig(ADC1,ADC_Channel_9,1,ADC_SampleTime_239Cycles5);
  40.         ADC_RegularChannelConfig(ADC1,ADC_Channel_17,2,ADC_SampleTime_239Cycles5);
  41.        
  42.         ADC_ITConfig(ADC1,ADC_IT_EOC,ENABLE);
  43.         ADC_Cmd(ADC1,ENABLE);
  44.         ADC_ResetCalibration(ADC1);
  45.         while(ADC_GetResetCalibrationStatus(ADC1));
  46.        
  47.         ADC_StartCalibration(ADC1);
  48.         while(ADC_GetCalibrationStatus(ADC1));
  49.         ADC_SoftwareStartConvCmd(ADC1,ENABLE);
  50. }

  51. void adc_nvic_init()
  52. {
  53.        
  54.         NVIC_InitTypeDef nvic;
  55.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  56.         nvic.NVIC_IRQChannel = ADC1_2_IRQn;
  57.         nvic.NVIC_IRQChannelCmd = ENABLE;
  58.         nvic.NVIC_IRQChannelPreemptionPriority = 1;
  59.         nvic.NVIC_IRQChannelSubPriority = 1;
  60.         NVIC_Init(&nvic);
  61.        
  62.         NVIC_InitTypeDef usart1;
  63.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  64.         usart1.NVIC_IRQChannel = USART1_IRQn;
  65.         usart1.NVIC_IRQChannelCmd = ENABLE;
  66.         usart1.NVIC_IRQChannelPreemptionPriority = 0;
  67.         usart1.NVIC_IRQChannelSubPriority= 0;
  68.         NVIC_Init(&usart1);
  69. }

  70. void usart_init()
  71. {
  72.          GPIO_InitTypeDef Uart_A;  
  73.       
  74.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA ,ENABLE);  
  75.     Uart_A.GPIO_Pin = GPIO_Pin_9;  
  76.     Uart_A.GPIO_Speed = GPIO_Speed_50MHz;  
  77.     Uart_A.GPIO_Mode = GPIO_Mode_AF_PP;  
  78.     GPIO_Init(GPIOA,&Uart_A);  
  79.       
  80.     Uart_A.GPIO_Pin = GPIO_Pin_10;  
  81.     Uart_A.GPIO_Speed = GPIO_Speed_50MHz;  
  82.     Uart_A.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  83.     GPIO_Init(GPIOA,&Uart_A);   
  84.        
  85.         USART_InitTypeDef Uart;  
  86.       
  87.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);  
  88.     Uart.USART_BaudRate = 115200;  
  89.     Uart.USART_HardwareFlowControl = USART_HardwareFlowControl_None;  
  90.     Uart.USART_Mode = USART_Mode_Tx;  
  91.     Uart.USART_Parity = USART_Parity_No;  
  92.     Uart.USART_StopBits = USART_StopBits_1;  
  93.     Uart.USART_WordLength = USART_WordLength_8b;  
  94.     USART_Init(USART1,&Uart);  
  95.       
  96.     USART_Cmd(USART1,ENABLE);  
  97.     USART_ClearFlag(USART1,USART_FLAG_TC);
  98. }
  99. int main()
  100. {
  101.         void PrintU16(uint16_t num);
  102.         void PrintHexU8(uint8_t data);

  103.         Adc_Init();
  104.         adc_nvic_init();
  105.         usart_init();
  106.         while(1)
  107.         {
  108.                 num = (uint16_t)(2.0f* ADC_ConvertedValue/ADC_ConvertedValue_1 *1.2f*100 );

  109.                 PrintU16(num);
  110.                 delay(1000);
  111.         }
  112. }

  113. void PrintU16(uint16_t num)
  114. {
  115.         void PrintHexU8(uint8_t data);
  116.         uint8_t w5,w4,w3,w2,w1;
  117.         w5 = num % 100000/10000;
  118.         w4 = num % 10000/1000;
  119.         w3 = num % 1000/100;
  120.         w2 = num % 100/10;
  121.         w1 = num % 10;
  122.         PrintHexU8('0' + w5);
  123.         PrintHexU8('0' + w4);
  124.         PrintHexU8('0' + w3);
  125.         PrintHexU8('0' + w2);
  126.         PrintHexU8('0' + w1);
  127. }

  128. void PrintHexU8(uint8_t data)
  129. {
  130.         car = data;
  131.         if(!(USART1->CR1 & USART_CR1_TXEIE))
  132.                 USART_ITConfig(USART1,USART_IT_TXE,ENABLE);//打开发送中断
  133. }

  134. void ADC1_2_IRQHandler()
  135. {
  136.         if(ADC_GetITStatus(ADC1,ADC_IT_EOC) == SET)
  137.         {if(count_1%2 == 0){
  138.                 ADC_ConvertedValue = ADC_GetConversionValue(ADC1);
  139.                 count_1++;
  140.         }else
  141.                         {
  142.                                 ADC_ConvertedValue_1 = ADC_GetConversionValue(ADC1);
  143.                                 count_1++;
  144.                         }
  145.         }
  146.         ADC_ClearITPendingBit(ADC1,ADC_IT_EOC);
  147. }

  148. void USART1_IRQHandler(void)
  149. {
  150.         if(USART_GetFlagStatus(USART1,USART_FLAG_TXE))
  151.         {
  152.                 USART1->CR1 &= ~USART_CR1_TXEIE;
  153.                 USART1->DR = car;
  154.                 while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);
  155.                 //USART1->CR1 &= ~USART_CR1_TXEIE;
  156.         }
  157.        
  158.         if(USART1->SR & USART_SR_RXNE)
  159.         {
  160.                 volatile int8_t com_data;
  161.                 com_data = USART1->DR;
  162.         }
  163. }
复制代码

————————————————
版权声明:家安


`ZB9ZS$(FO4RB}3Y0%VH5TY.png
收藏 评论0 发布时间:2023-1-4 21:03

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版