完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
本文简单介绍了STM32F103C8,通过中断方式读取电压,不过最后楼主读取参考电压失败,还没有找到错误,所以读取的电压只能十六进制显示,如有不便请忽略本文!
本文的介绍按照一般流程来走: 1,串口的初始化 2,ADC初始化 3,中断初始化 4,编写中断函数 5,编写主函数 接下来详细介绍: 1,串口的初始化: void usart_init() { GPIO_InitTypeDef Uart_A; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA ,ENABLE); Uart_A.GPIO_Pin = GPIO_Pin_9; Uart_A.GPIO_Speed = GPIO_Speed_50MHz; Uart_A.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOA,&Uart_A); Uart_A.GPIO_Pin = GPIO_Pin_10; Uart_A.GPIO_Speed = GPIO_Speed_50MHz; Uart_A.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA,&Uart_A); USART_InitTypeDef Uart; RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE); Uart.USART_BaudRate = 115200; Uart.USART_HardwareFlowControl = USART_HardwareFlowControl_None; Uart.USART_Mode = USART_Mode_Tx; Uart.USART_Parity = USART_Parity_No; Uart.USART_StopBits = USART_StopBits_1; Uart.USART_WordLength = USART_WordLength_8b; USART_Init(USART1,&Uart); USART_Cmd(USART1,ENABLE); USART_ClearFlag(USART1,USART_FLAG_TC); } 关于本段代码,我前面写的文章STM32基础设计(3)有详细讲解,此处不再赘述。 2,ADC初始化 typedef struct {//配置ADC的模式,一个ADC是独立模式,2个是双模式 uint32_t ADC_Mode; /*!《 Configures the ADC to operate in independent or dual mode. This parameter can be a value of @ref ADC_mode */ //配置ADC是否使用扫描,单通道不扫描,多通道扫描 FunctionalState ADC_ScanConvMode; /*!《 Specifies whether the conversion is performed in Scan (multichannels) or Single (one channel) mode. This parameter can be set to ENABLE or DISABLE */ //配置ADC是单次转换还是连续转换 FunctionalState ADC_ContinuousConvMode; /*!《 Specifies whether the conversion is performed in Continuous or Single mode. This parameter can be set to ENABLE or DISABLE. */ //外部触发选择 uint32_t ADC_ExternalTrigConv; /*!《 Defines the external trigger used to start the analog to digital conversion of regular channels. This parameter can be a value of @ref ADC_external_trigger_sources_for_regular_channels_conversion */ //转换结果数据对其方式 uint32_t ADC_DataAlign; /*!《 Specifies whether the ADC data alignment is left or right. This parameter can be a value of @ref ADC_data_align */ //ADC转换的通道数目 uint8_t ADC_NbrOfChannel; /*!《 Specifies the number of ADC channels that will be converted using the sequencer for regular channel group. This parameter must range from 1 to 16. */ }ADC_InitTypeDef; 下面粘贴代码: void Adc_Init() { ADC_InitTypeDef adc;//定义ADC结构的变量 GPIO_InitTypeDef io_b;//定义串口结构体变量 ,开发板上的电源接的是GPIOB端口的 1引脚,查数据手册,其为ADC1的9通道 RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOB,ENABLE);//开时钟(即把心脏激活) RCC_ADCCLKConfig(RCC_PCLK2_Div6); io_b.GPIO_Pin = GPIO_Pin_1;//设置端口引脚为 引脚1 io_b.GPIO_Mode = GPIO_Mode_AIN;//设置为输入模式 io_b.GPIO_Speed = GPIO_Speed_50MHz;//最高速率为50MHz GPIO_Init(GPIOB,&io_b);初始化引脚 ADC_DeInit(ADC1);先将外设ADC1的全部寄存器重设为默认值 ADC_TempSensorVrefintCmd(ENABLE);谁能外部参照电压(勿忘) adc.ADC_Mode = ADC_Mode_Independent;设置ADC为独立模式 adc.ADC_ScanConvMode = ENABLE;使能扫描模式 adc.ADC_ContinuousConvMode = ENABLE;使能连续扫描 adc.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;不使用外部触发 adc.ADC_DataAlign = ADC_DataAlign_Right;数据右对齐 adc.ADC_NbrOfChannel = 2;来制定用几个ADC通达(勿忘) ADC_Init(ADC1,&adc);初始化ADC寄存器 ADC_RegularChannelConfig(ADC1,ADC_Channel_9,1,ADC_SampleTime_239Cycles5);制定用哪个ADC转换、第几个通道,转换的顺序、转换的周期 ADC_RegularChannelConfig(ADC1,ADC_Channel_17,2,ADC_SampleTime_239Cycles5); //这里需要根据数据手册来设定通道,数据手册上会说明那个引脚对应那个通道,外接电源接到那个引脚上就可以了,必须按照数据手册的要求来,不然肯定会出错,博主在这里就有一个很大很大的教训,望读者谨记 ADC_ITConfig(ADC1,ADC_IT_EOC,ENABLE);打开ADC中断 ADC_Cmd(ADC1,ENABLE);使能ADC1 ADC_ResetCalibration(ADC1);复位ADC1的校准寄存器 while(ADC_GetResetCalibrationStatus(ADC1));等待校准寄存器复位完成 ADC_StartCalibration(ADC1);开始ADC1校准 while(ADC_GetCalibrationStatus(ADC1));等待ADC1校准完成 ADC_SoftwareStartConvCmd(ADC1,ENABLE);使能指定的ADC1的软件转换启动功能 } 3.中断初始化 void adc_nvic_init() { NVIC_InitTypeDef nvic;定义中断结构体 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);设置中断分组 nvic.NVIC_IRQChannel = ADC1_2_IRQn;制定专断通道 nvic.NVIC_IRQChannelCmd = ENABLE;使能中断 nvic.NVIC_IRQChannelPreemptionPriority = 1;抢占优先级 nvic.NVIC_IRQChannelSubPriority = 1;子优先级 NVIC_Init(&nvic);初始化 NVIC_InitTypeDef usart1;定义中断结构体 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);设置中断分组 usart1.NVIC_IRQChannel = USART1_IRQn;指定中断通道 usart1.NVIC_IRQChannelCmd = ENABLE;设能中断通道 usart1.NVIC_IRQChannelPreemptionPriority = 0;抢占优先级 usart1.NVIC_IRQChannelSubPriority= 0;子优先级 NVIC_Init(&usart1);中断初始化 } 博主在这里遇到一个问题,该问题时,中断分组的设置,上面两段程序得分别设置中断分组,要不然会有一个中断不会执行(没有再次设置中断分组的那个),不知道是博主代码规范的问题还是就必须这样设置。博主还未搞懂,如果读者有知道这个问题答案的,请在评论里赐教,不胜感激。 4,编写中断函数 先粘贴代码: void ADC1_2_IRQHandler() { if(ADC_GetITStatus(ADC1,ADC_IT_EOC) == SET)这里使用来判断,如果已经转换完成EOC位为1,具体请查看参考手册ADC状态寄存器ADC_SR的eEOC位 {if(count_1%2 == 0){代码中的if语句中的嵌套if语句是用来区分外接电源电压和内部参考电压的。具体见下面的解释 ADC_ConvertedValue = ADC_GetConversionValue(ADC1); count_1++; }else { ADC_ConvertedValue_1 = ADC_GetConversionValue(ADC1); //ADC_ConvertedValue_1 = ADC1-》DR; count_1++; } } ADC_ClearITPendingBit(ADC1,ADC_IT_EOC); } void USART1_IRQHandler(void) { if(USART_GetFlagStatus(USART1,USART_FLAG_TXE))判断是否可以发送数据 { USART1-》CR1 &= ~USART_CR1_TXEIE;在这里笔者也碰到了问题,详见下文 USART1-》DR = car; while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET); //USART1-》CR1 &= ~USART_CR1_TXEIE; } if(USART1-》SR & USART_SR_RXNE)判断是否可以接收数据 { volatile int8_t com_data; com_data = USART1-》DR; } } 在ADC中断服务函数中,代码中的if语句中的嵌套if语句是用来区分外接电源电压和内部参考电压的,因为第一次接受的是外部电源电压,第二次接受的是内部参考电压,所以可以利用奇偶数,即偶数用ADC_ConvertedValue来存放外部电源电压值,奇数时用ADC_ConvertedValue_1来存放参考电压值。但是,笔者发现,这样会失败,经过串口调试发现两次接受到的值都一样,笔者初步认为,可能是ADC的转换速率太快了,具体什么歌情况还不清楚,等下一个基础设计ADC转换(DMA方式)的时候在细究。 笔者,在调试程序的时候发现,通过中断的方式进行串口通信必须在给DR赋值之前将CR1寄存器的 TXEIE寄存器置0,以防止DE接受完数据后再次进入中断,要不然将数据赋值给DR后会一直进入中断(笔者在调试的时候发现,会一直重复输出一个值,笔者猜测这不是因为中断结束不了,而是因为,嵌套了N层循环,但是根据STM32参考手册的543页,TXEIE为明明解释是由软件设置,笔者在主函数里设置了TXEIE为0,发现没有用,如果在中断服务函数中不再次清零,就跳不出中断。),另外DR接受完数据后,还要加一句 while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET); 要是没有这一句,串口调试时发现,一个值连续打印两次。(笔者猜测是不是因为电脑速度太快了。) 以上两个问题,笔者还没有找到原因,只是找到了解决方法,希望看到这篇文章的读者,如果知道原因,请不吝赐教,在下不胜感激。 5,编写主函数 int main() { void PrintU16(uint16_t num); void PrintHexU8(uint8_t data); Adc_Init(); adc_nvic_init(); usart_init(); while(1) { num = (uint16_t)(2.0f* ADC_ConvertedValue/ADC_ConvertedValue_1 *1.2f*100 );参考电压是1.2f通过比例关系算出实际电压。 PrintU16(num); delay(1000); } } |
|
|
|
笔者并没有计算出准确的电压值,只是采集到两个电压值,笔者猜测,可能是因为ADC的转换速率太快,导致笔者的 通过奇偶数来区分内部电压和外部电压不管用了,笔者还在思考解决方式,如果读者有好的方法,请指教。
本文到此结束,下面是完整代码: #include《stm32f10x.h》 #define uint unsigned int #define uchar unsigned char char car; static char count_1=0;//当做奇偶数 uint16_t ADC_ConvertedValue;//存放电源电压 uint16_t ADC_ConvertedValue_1;//存放内部参照电压 static uint16_t num=0; void delay(uint n) { int i,j; for(i=0;i《n;i++) for(j=0;j《8500;j++); } void Adc_Init() { ADC_InitTypeDef adc; GPIO_InitTypeDef io_b; RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOB,ENABLE); RCC_ADCCLKConfig(RCC_PCLK2_Div6); io_b.GPIO_Pin = GPIO_Pin_1; io_b.GPIO_Mode = GPIO_Mode_AIN; io_b.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB,&io_b); ADC_DeInit(ADC1); ADC_TempSensorVrefintCmd(ENABLE); adc.ADC_Mode = ADC_Mode_Independent; adc.ADC_ScanConvMode = ENABLE; adc.ADC_ContinuousConvMode = ENABLE; adc.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; adc.ADC_DataAlign = ADC_DataAlign_Right; adc.ADC_NbrOfChannel = 2; ADC_Init(ADC1,&adc); ADC_RegularChannelConfig(ADC1,ADC_Channel_9,1,ADC_SampleTime_239Cycles5); ADC_RegularChannelConfig(ADC1,ADC_Channel_17,2,ADC_SampleTime_239Cycles5); ADC_ITConfig(ADC1,ADC_IT_EOC,ENABLE); ADC_Cmd(ADC1,ENABLE); ADC_ResetCalibration(ADC1); while(ADC_GetResetCalibrationStatus(ADC1)); ADC_StartCalibration(ADC1); while(ADC_GetCalibrationStatus(ADC1)); ADC_SoftwareStartConvCmd(ADC1,ENABLE); } void adc_nvic_init() { NVIC_InitTypeDef nvic; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); nvic.NVIC_IRQChannel = ADC1_2_IRQn; nvic.NVIC_IRQChannelCmd = ENABLE; nvic.NVIC_IRQChannelPreemptionPriority = 1; nvic.NVIC_IRQChannelSubPriority = 1; NVIC_Init(&nvic); NVIC_InitTypeDef usart1; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); usart1.NVIC_IRQChannel = USART1_IRQn; usart1.NVIC_IRQChannelCmd = ENABLE; usart1.NVIC_IRQChannelPreemptionPriority = 0; usart1.NVIC_IRQChannelSubPriority= 0; NVIC_Init(&usart1); } void usart_init() { GPIO_InitTypeDef Uart_A; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA ,ENABLE); Uart_A.GPIO_Pin = GPIO_Pin_9; Uart_A.GPIO_Speed = GPIO_Speed_50MHz; Uart_A.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOA,&Uart_A); Uart_A.GPIO_Pin = GPIO_Pin_10; Uart_A.GPIO_Speed = GPIO_Speed_50MHz; Uart_A.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA,&Uart_A); USART_InitTypeDef Uart; RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE); Uart.USART_BaudRate = 115200; Uart.USART_HardwareFlowControl = USART_HardwareFlowControl_None; Uart.USART_Mode = USART_Mode_Tx; Uart.USART_Parity = USART_Parity_No; Uart.USART_StopBits = USART_StopBits_1; Uart.USART_WordLength = USART_WordLength_8b; USART_Init(USART1,&Uart); USART_Cmd(USART1,ENABLE); USART_ClearFlag(USART1,USART_FLAG_TC); } int main() { void PrintU16(uint16_t num); void PrintHexU8(uint8_t data); Adc_Init(); adc_nvic_init(); usart_init(); while(1) { num = (uint16_t)(2.0f* ADC_ConvertedValue/ADC_ConvertedValue_1 *1.2f*100 ); PrintU16(num); delay(1000); } } void PrintU16(uint16_t num) { void PrintHexU8(uint8_t data); uint8_t w5,w4,w3,w2,w1; w5 = num % 100000/10000; w4 = num % 10000/1000; w3 = num % 1000/100; w2 = num % 100/10; w1 = num % 10; PrintHexU8(‘0’ + w5); PrintHexU8(‘0’ + w4); PrintHexU8(‘0’ + w3); PrintHexU8(‘0’ + w2); PrintHexU8(‘0’ + w1); } void PrintHexU8(uint8_t data) { car = data; if(!(USART1-》CR1 & USART_CR1_TXEIE)) USART_ITConfig(USART1,USART_IT_TXE,ENABLE);//打开发送中断 } void ADC1_2_IRQHandler() { if(ADC_GetITStatus(ADC1,ADC_IT_EOC) == SET) {if(count_1%2 == 0){ ADC_ConvertedValue = ADC_GetConversionValue(ADC1); count_1++; }else { ADC_ConvertedValue_1 = ADC_GetConversionValue(ADC1); count_1++; } } ADC_ClearITPendingBit(ADC1,ADC_IT_EOC); } void USART1_IRQHandler(void) { if(USART_GetFlagStatus(USART1,USART_FLAG_TXE)) { USART1-》CR1 &= ~USART_CR1_TXEIE; USART1-》DR = car; while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET); //USART1-》CR1 &= ~USART_CR1_TXEIE; } if(USART1-》SR & USART_SR_RXNE) { volatile int8_t com_data; com_data = USART1-》DR; } } |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1837 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1645 浏览 1 评论
1110 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
743 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1698 浏览 2 评论
1955浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
763浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
591浏览 3评论
608浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
575浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2025-1-2 04:40 , Processed in 1.068723 second(s), Total 80, Slave 64 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (威廉希尔官方网站 图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号