一、基本原理
对于Source-Free RC电路,其电容放电的特性可以描述为:
其中V0是电容的初始电压,t是放电时间,R是串接的电阻阻值,C是电容值,v(t)是t时刻电容上的电压。因此,若已知V0、R、以及t1时刻的电压Vt1,便可求得C:
二、如何控制和测量
如上图所示,大致步骤为:1)由GPIO通过电阻R给电容C充电至Vcc;2)该GPIO输出0,电容C通过R进行放电,同时Timer开始计时、CA+开启;3)当电容电压放电至参考电压(此处是0.25Vcc)时,比较器CA+输出端出现电平变化;4)中断程序捕获这一变化,并利用Timer的capture mode获得该时刻的时间,最后通过以上方程计算电容值。
上图中R推荐采用1%精度的电阻,以提高测试精度。
三、状态转换图
复制代码
1 // C meter 2015.9.26
2 //
3 // P1.5(TA0.0) --[||||]----------- P1.4(CA3)
4 // R=10kOhm |
5 // -----
6 // cap -----
7 // |
8 // GND
9 // http://zlbg.cnblogs.com
10 /////////////////////////////////////////
11
12 #include "io430.h"
13
14 #define LED1 BIT0 // P1.0, red led
15 #define LED2 BIT6 // P1.6, green led
16
17 #define VMEAS BIT4 // P1.4(CA4) for voltage measurement of the cap
18 #define VCTRL BIT5 // P1.5(TA0.0) for voltage control
19 #define PUSH2 BIT3 // P1.3, button
20
21 #define RXD BIT1 //P1.1
22 #define TXD BIT2 //P1.2
23
24 #define READY 0
25 #define CHARGING 1
26 #define DISCHARGING 2
27 #define FINISH_DC 3
28
29 #define R_SERIES 10000 //10kOhm
30 #define LN4 1.3863
31
32 //functions for C meter
33 void P1Init(void);
34 void TA0Init(void);
35 void CAInit(void);
36
37 void setReadyStatus(void);
38
39 //functions for printf()
40 void sendByte(unsigned char);
41 void printf(char *, ...);
42 void initUART(void);
43
44 char state = READY;
45 unsigned char overflowsCharging = 0;
46 unsigned char overflowsDischarging = 0;
47 unsigned char i = 0;
48 float capacitance = 0; // unit: nF
49
50 void main(void)
51 {
52 // Stop watchdog timer to prevent time out reset
53 WDTCTL = WDTPW + WDTHOLD;
54
55 // DCO setup
56 BCSCTL1 = CALBC1_1MHZ; //running at 1Mhz
57 DCOCTL = CALDCO_1MHZ;
58
59 // P1 setup
60 P1Init();
61
62 // Timer0 setup
63 TA0Init();
64
65 // CA setup
66 CAInit();
67
68 // UART setup
69 initUART();
70
71 setReadyStatus();
72
73 __enable_interrupt();
74
75 // enter LP mode
76 LPM0;
77
78 }
79
80
81 void P1Init(void)
82 {
83 P1OUT = 0;
84
85 // set P1.3 (PUSH2) as input with pullup
86 P1OUT |= PUSH2;
87 P1REN |= PUSH2;
88
89 // set P1.0, P1.6, P1.5 as output
90 P1DIR |= LED1 + LED2 + VCTRL;
91
92 // enable P1.3 interrupt
93 P1IES |= PUSH2; // high -> low transition
94 P1IFG &= ~PUSH2; // clear the flag
95 P1IE |= PUSH2;
96 }
97
98 void TA0Init(void)
99 {
100 // use SMCLK (1MHz), no div, clear, halt
101 TA0CTL = TASSEL_2 + ID_0 + MC_0 + TACLR;
102
103 // TA0CCTL0: compare mode, enable interrupt
104 TA0CCTL0 = CCIE;
105
106 // TA0CCTL1: capture mode, no capture, CCI1B(CAOUT) input, syn capture
107 // interrupt enabled
108 TA0CCTL1 = CCIS_1 + SCS + CAP + CCIE;
109 }
110
111 void CAInit(void)
112 {
113 //0.25 Vcc ref on V+, halt
114 CACTL1 = CAREF_1 + CAIES;
115 // input CA4 (P1.4), remove the jumper) on V-, filter on
116 CACTL2 = P2CA3 + CAF;
117 }
118
119 void setReadyStatus(void)
120 {
121 state = READY;
122 // light led2 and turn off led1 to indicate ready
123 P1OUT &= ~LED1;
124 P1OUT |= LED2;
125
126 //stop and clear timer, stop T0_A1 capture & CA+
127 TA0CTL = TASSEL_2 + ID_0 + MC_0 + TACLR;
128 TA0CCTL1 &= ~CM_3;
129 CACTL1 &= ~CAON;
130
131 overflowsCharging = 0;
132 }
133
134 void initUART(void) {
135 //config P1.1 RXD, P1.2 TXD
136 P1SEL |= TXD + RXD;
137 P1SEL2 |= TXD + RXD;
138
139 //reset UCA0, to be configured
140 UCA0CTL1 = UCSWRST;
141 //config
142 UCA0CTL1 |= UCSSEL_2; //SMCLK
143 UCA0BR0 = 104;
144 UCA0BR1 = 0;//1MHz baut rate = 9600 8-N-1
145 UCA0MCTL = UCBRS0; // Modulation UCBRSx = 1
146 //make UCA0 out of reset
147 UCA0CTL1 &= ~UCSWRST;
148 }
149
150
151 void sendByte(unsigned char byte )
152 {
153 while (!(IFG2&UCA0TXIFG)); // USCI_A0 TX buffer ready?
154 UCA0TXBUF = byte; // TX -> RXed character
155 }
156
157 #pragma vector = PORT1_VECTOR
158 __interrupt void P1_ISR(void)
159 {
160 if((P1IFG & PUSH2) == PUSH2)
161 {
162 P1IFG &= ~PUSH2; //clear the flag
163 switch(state)
164 {
165 case READY:
166 state = CHARGING;
167 // light LED1 and turn off LED2, indicate a busy status
168 P1OUT |= LED1;
169 P1OUT &= ~LED2;
170 //start timer, continuous mode
171 TACTL |= MC_2;
172 //start charging
173 P1OUT |= VCTRL;
174 break;
175 default:
176 break;
177 }
178
179 }
180 else
181 {
182 P1IFG = 0;
183 }
184 }
185
186 #pragma vector = TIMER0_A0_VECTOR
187 __interrupt void CCR0_ISR(void)
188 {
189 switch(state)
190 {
191 case CHARGING:
192 if (++overflowsCharging == 50) // wait 6.5535*50 = 3.28s
193 {
194 state = DISCHARGING;
195 CACTL1 |= CAON; // turn on CA+
196 TA0CCTL1 |= CM_1; // start TA1 capture on rising edge
197 P1OUT &= ~VCTRL; // start discharging
198 overflowsDischarging = 0;
199 }
200 break;
201 case DISCHARGING:
202 overflowsDischarging++;
203 default:
204 break;
205
206 }
207
208 }
209
210 #pragma vector = TIMER0_A1_VECTOR
211 __interrupt void CCR1_ISR(void)
212 {
213 TA0CTL &= ~MC_3; //stop timer
214 TA0CCTL1 &= ~CCIFG; // clear flag
215 switch(state)
216 {
217 case DISCHARGING:
218 state = FINISH_DC;
219 capacitance = (overflowsDischarging*65536 + TA0CCR1)*1000 / (R_SERIES*LN4); //nF
220 //send result to PC
221 printf("Capatitance: %n", (long unsigned)capacitance);
222 printf(" nF\r\n");
223
224 setReadyStatus();
225 break;
226 default:
227 break;
228 }
229 }
复制代码
printf.c程序:为将电容结果通过UART输出至PC显示,以下这段程序实现了printf()函数,代码来自于NJC's MSP430 LaunchPad Blog博客和oPossum的代码。
View Code
五、测试结果
串口工具推荐使用Realterm,选择MSP430 Launchpad对应的串口号,串口波特率设为9600、8-N-1。电路连接好后,按下S2键开始测量,测量完成后,在Realterm上可以显示测量结果。板上的红、绿LED灯显示了工作状态,绿灯表示空闲(测量结束),红灯表示正在测量。试测了一个标称47uF的电容,结果如下图所示。