基于STM32的电阻、电容测量(NE555芯片RC振荡法)

慈云数据 2024-04-23 技术支持 76 0

文章目录

  • 前言
  • 一、电路图
    • 1.电阻测量公式
    • 2.电容测量公式
    • 二、代码实现
      • 1.外部中断代码
      • 2.定时器中断处理数据
      • 总结

        前言

        做的一个关于电阻和电容的测量电路,都是比较通用的。经过实际测试,电容测量电路还是可以的,电阻测量电路有一个缺点就是,随着测量时长的推移,在小电阻的测量时,比如0-100欧姆测量时,检测到的RC震荡频率会增加, 所以小电阻需要校正一下,否则小电阻容易出现较大的偏差。大电阻的话测量精度还是可以的。


        一、电路图

        在这里插入图片描述

        具体的电阻电容选值已经标好了,这个电阻电容的选值对应的测量范围为电阻10-1M欧姆,电容1-220nf左右。输出F口的作用主要在于通过两个自锁开关切换电阻或者电容的测量,只用占用单片机的一个IO口,这个IO口进行外部中断。

        1.电阻测量公式

        在这里插入图片描述

        FR为我们测量到的频率

        在实际电路中,R12和R13均被设置为1.5K。由于单片机内部被设定为每隔一秒钟检测一次脉冲的个数,故在极限状况下可以测的大范围的电阻。若需要改进优化范围,可以改变R13和R12电阻的大小,使其产生不同的谐振状态,从而实现不同范围的需求。

        2.电容测量公式

        在这里插入图片描述

        同样FC为测的电容频率

        二、代码实现

        1.外部中断代码

        #include "exti.h"
        #include "key.h"
        #include "delay.h"
        #include "stm32f10x_exti.h" 
        long Pulsenum;	//脉冲个数 
        void EXTIX_Init(void)//外部中断初始化函数
        {
          EXTI_InitTypeDef EXTI_InitStructure;
          NVIC_InitTypeDef NVIC_InitStructure;
          RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//外部中断,需要使能AFIO时钟
          GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource15);
          EXTI_InitStructure.EXTI_Line=EXTI_Line15;
          EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;	
          EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
          EXTI_InitStructure.EXTI_LineCmd = ENABLE;
          EXTI_Init(&EXTI_InitStructure);	  	//根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器
          NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;			//使能按键所在的外部中断通道
          NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00;	//抢占优先级2, 
          NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01;					//子优先级1
          NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;								//使能外部中断通道
          NVIC_Init(&NVIC_InitStructure); 
        }
        void EXTI15_10_IRQHandler(void)
        {
          Pulsenum++;
          EXTI_ClearITPendingBit(EXTI_Line15); 
        }
        

        外部中断主要是为了采集电阻电容端口对应的频率,此处的话是用PA15作为中断触发口。

        2.定时器中断处理数据

        代码如下(示例):

        #include "timer.h"
        #include "led.h"
        #include "usart.h"
        #include "adc.h"
        #include "exti.h"
        #include "main.h"
        //电阻--------------------------------
        unsigned long  Z1=14026950.00;
        float RZ=0;
        unsigned long   RX=0;
        unsigned long   RX2=0;
        unsigned long   RX3=0;
        unsigned long   RX4=0;
        unsigned long   RX5=0;
        unsigned long   RX6=0;
        unsigned long   RX7=0;
        unsigned long   RX8=0;
        unsigned long   RX9=0;
        unsigned long   R=0;
        //电容--------------------------------
        float CZ=0;
        float CX=0;
        unsigned long   x;
        void TIM3_Int_Init(u16 arr,u16 psc)
        {
          TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
        	NVIC_InitTypeDef NVIC_InitStructure;
        	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
        	TIM_TimeBaseStructure.TIM_Period = arr;
        	TIM_TimeBaseStructure.TIM_Prescaler =psc;  
        	TIM_TimeBaseStructure.TIM_ClockDivision = 0;
        	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  
        	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);  
        	TIM_ITConfig(TIM3, TIM_IT_Update|TIM_IT_Trigger,ENABLE);
        	NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;  
        	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  
        	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;  
        	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 
        	NVIC_Init(&NVIC_InitStructure);  
        	TIM_Cmd(TIM3, ENABLE);  							 
        }
        void TIM3_IRQHandler(void)   //TIM3中断
        {
        	static u16 count;
        	if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //检查指定的TIM中断发生与否:TIM 中断源 
        	{
        		/*电阻采集*/
        		count++;
            if(count >= 1000)
        	  {
        			count = 0;
        			x = Pulsenum;   //测得的脉冲值数量,也就是FR
        			if(mode==3)
        			{
        				if(x8&&x30&&x300&&x1000&&x>1;       //对应的除以2
                if(RX>=1490)
                {
                  RX=RX-1490;
                }else
                {
        			    RX=0;
                }
        			  if(x==0){RX=0;RX2=0;RX3=0;RX4=0;RX5=0;RX6=0;RX7=0;RX8=0;RX9=0;}//如果测得的频率为0,则此次测得的结果都为0
                if(RX>2000000){RX=2000000;}                                    //如果电阻测得的结果大于1M欧姆,则结果就等于1M欧姆
        			  RX2=(RX+RX3+RX4+RX5+RX6+RX7+RX8+RX9)>>3;                //求平均提高精度
        			  RX9=RX8;RX8=RX7;RX7=RX6;RX6=RX5;RX5=RX4;RX4=RX3;RX3=RX; //依次赋值
        				Pulsenum = 0;
        			}
        			/*电容采集*/
        			else if(mode==4)
        			{
        				CZ=708317/x-7;
        				if(CZ>9999999)CZ=9999999;  //限制最高值
        				Pulsenum = 0;
        			}
        		}
        		TIM_ClearITPendingBit(TIM3, TIM_IT_Update  );  //清除TIMx的中断待处理位:TIM 中断源 
        	}
        }
        

        从上往下看,在电阻参数设置一栏里面,定义了RX-RX9还有R,这个主要是为了提高电阻测量的精度。在实际的测试过程中电阻需要测量八次才能得到一个稳定的电阻值,也就是8s左右得到稳定的电阻值。Z1是我们设置好的一个参数。通过调节这个参数可以改变我们的精度。电容参数设置也是一样,x是我们每秒检测到的一个频率值。通过外部中断里面的pulse赋值。

        在定时器三中断里面有一个count计数,此处定时器设置的频率为1KHz,因此count计数到1000的时候自动归零,也代表过了一秒钟,所以进行一次脉冲数的赋值给x。mode是我们设置的检测模式,此处当模式为3的时候进行电阻的测量,模式为4的时候进行电容的测量。

        x的值越小,代表测量的电阻阻值越大。一般我调试的时候会进行划分区间段的调试,这样能够尽可能地提升测量的精度。通过keil的软件仿真观测不同阻值对应不同x值,从而改变Z1的大小,Z1越大,阻值就越大。Z1越小,阻值就越小。通过改变Z1的大小,从而获得某个区间段更优的数据。在if(RX>=1490)里面,这个1490的值是不确定的,是要根据你测量小电阻的时候来。假设如果10欧姆的电阻测量起来以后显示20欧姆的话,请把多余的这部分带入到上面的公式里面,修改1490的大小,如果大于真实电阻值的话,就把这个1490略微增大点,如果小于真实电阻值的话,就把1490稍微减小一点。

        电容采集这边的话就是改变708317这个值,你可以用小电容定标,也可以用大电容定标,这都是没问题的,通过改变这个值获得更高精度的电容测量值。前提是测量的电容都是无极性电容。

        在主函数中,只需要调用着两个数值即可,即可获得想要的电阻电容值。


        总结

        码字不易,希望大家三连支持一下!!你们的支持就是我分享的动力!

微信扫一扫加客服

微信扫一扫加客服

点击启动AI问答
Draggable Icon