Hallo zusammen,
ich hänge fest...
Folgendes:
Ich möchte mit dem atxmega16a4 den Spannungsabfall über ein
Shunt-Widerstand messen, und mir den Strom auf einem Display ausgeben,
außerdem möchte ich mir die Möglichkeit vorbehalten, die
Versorgungsspannung zu unterbrechen, wenn ein bestimmter Strom
überschritten wird.
Der Shunt Widerstand liegt am gleichen ground wie der uC. Dennoch wollte
ich gerne den Differenz-Modus mit Gain benutzen um die Referenzen DIREKT
am Widerstand zu messen.
Der Widerstand ist nicht sooo klein: 1/3 Ohm, und ich möchte damit
Spannungen bis 700mA messen können.
Spannungsquelle ist ein PC Netzteil. Versorgung für den uC GND -> 3,3 V.
Zu messender Strom GND -> 5V.
Beide Spannung sind geglättet durch Kondensatoren verschiedener Größe,
wobei ich mit dem Oszilloskop auch keine Spannungsschwankungen
feststellen konnte.
Der Aufbau des Ganzen ist auf einem Steckbrett. Deshalb sind gewisse
Schwankungen sicher nicht ungewöhnlich. Jedoch schwanken die
Messergebnisse mit mehr als 20%. Das finde ich viel.
Hier der relevante Code:
1 | #include "main.h"
|
2 | #include "bla/iox16a4.h"
|
3 | #include <inttypes.h>
|
4 |
|
5 | #include <stdio.h>
|
6 | #include <stdint.h>
|
7 |
|
8 | #include <stddef.h>
|
9 |
|
10 |
|
11 | #include "includes/lcd.c"
|
12 | #include "includes/uart/uart.c"
|
13 | #include "includes/out.c"
|
14 | #include "includes/adc.c"
|
15 | #include "includes/osc.c"
|
16 |
|
17 |
|
18 | void init_uart(void);
|
19 |
|
20 |
|
21 | int16_t Result = 234;
|
22 |
|
23 | float ResultVolts;
|
24 |
|
25 | int main(void)
|
26 | {
|
27 | PORTD.DIR = 0xff;
|
28 | PORTD.OUT = 0x00;
|
29 |
|
30 |
|
31 | ext_osc_init();
|
32 | uart_init();
|
33 | adc_init();
|
34 |
|
35 | printf_init();
|
36 |
|
37 | lcd_init();
|
38 |
|
39 | // *** Interruptcontroller: Highlevelinterrupts aktivieren ***
|
40 | PMIC.CTRL |= PMIC_HILVLEN_bm;
|
41 | //************************************************************
|
42 | sei();
|
43 |
|
44 | while(1)
|
45 | {
|
46 | Result = adc_read();
|
47 | _delay_ms(200);
|
48 | if(Result >= 60000)
|
49 | Result = 0;
|
50 |
|
51 | ResultVolts = (float) (Result*1.75)/4096;
|
52 | printf("ADC Ch. 0: %1.3f \n", ResultVolts);
|
53 | printf("ADC Ch. 0: %u \n", Result);
|
54 | }
|
55 | }
|
adc.c:
1 | #include "includes/adc.h"
|
2 | #include <bla/iox16a4.h>
|
3 |
|
4 |
|
5 | void adc_init(void)
|
6 | {
|
7 | PORTA.DIR = 0;
|
8 | ADCA.CTRLA |= ADC_ENABLE_bm; // enable adc
|
9 | ADCA.CTRLB = ADC_CONMODE_bm | ADC_RESOLUTION_12BIT_gc; // 12 bit signed conversion (pos 11bits)
|
10 | ADCA.REFCTRL = ADC_REFSEL_INT1V_gc | 0x02; // internal 1V bandgap reference
|
11 | ADCA.PRESCALER = ADC_PRESCALER_DIV512_gc; // peripheral clk/16 (2MHz/16=125kHz)
|
12 | ADCA.CH0.CTRL = ADC_CH_INPUTMODE_DIFFWGAIN_gc | ADC_CH_GAIN_16X_gc; // differential, 4x front end gain
|
13 | ADCA.CH0.MUXCTRL = ADC_CH_MUXPOS_PIN2_gc | ADC_CH_MUXNEG_PIN4_gc; // PORTA:2 wrt PORTA:4
|
14 | ADCA.CH0.INTCTRL = ADC_CH_INTLVL_HI_gc; // hi level interrupt
|
15 | ADCA.EVCTRL = ADC_EVSEL_0123_gc | ADC_EVACT_CH0_gc; // trigger ch0 conversion on event0
|
16 |
|
17 | ADCA.CALL = adc_read_calibration_byte(offsetof(NVM_PROD_SIGNATURES_t, ADCACAL0));
|
18 | ADCA.CALH = adc_read_calibration_byte(offsetof(NVM_PROD_SIGNATURES_t, ADCACAL1));
|
19 | }
|
20 |
|
21 | int16_t adc_read(void)
|
22 | {
|
23 | int16_t result;
|
24 | ADCA.CH0.CTRL |= ADC_CH_START_bm;
|
25 | while(!ADCA.CH0.INTFLAGS);
|
26 | result = ADCA.CH0RES;
|
27 | return result;
|
28 | }
|
29 |
|
30 |
|
31 |
|
32 |
|
33 | uint8_t adc_read_calibration_byte(uint8_t index)
|
34 | {
|
35 | uint8_t result;
|
36 |
|
37 | /* Load the NVM Command register to read the calibration row. */
|
38 | NVM_CMD = NVM_CMD_READ_CALIB_ROW_gc;
|
39 | result = pgm_read_byte(index);
|
40 |
|
41 | /* Clean up NVM Command register. */
|
42 | NVM_CMD = NVM_CMD_NO_OPERATION_gc;
|
43 |
|
44 | return(result);
|
45 | }
|
An alle die sich diesen Roman durchlesen um mir zu helfen:
Vielen Lieben Dank!