Измерение тока и напряжения – одна из задач, которая достаточно часто возникает перед радиолюбителями. Наиболее часто она востребована при отладке работы электронных схем. В данной статье мы рассмотрим создание цифрового амперметра на микроконтроллере PIC и датчике тока ACS712, который будет способен проводить измерения как в цепях постоянного, так и в цепях переменного тока, с величиной измеряемого тока в диапазоне 0-30A с точностью 0.3A.
Также на нашем сайте вы можете посмотреть следующие проекты амперметров:
- амперметр на 100 мА на микроконтроллере AVR ATmega8;
- цифровой амперметр на основе Arduino Uno;
- ваттметр на Arduino – измерение напряжения, тока и мощности.
Необходимые компоненты
- Микроконтроллер PIC16F877A (купить на AliExpress).
- Держатель микросхем на 40 контактов (купить на AliExpress).
- Программатор PICkit 3 (купить на AliExpress).
- Кварцевый генератор 20 МГц (купить на AliExpress).
- Регулятор напряжения 7805 (купить на AliExpress).
- ЖК дисплей 16х2 (купить на AliExpress).
- Датчик тока ACS712 (купить на AliExpress).
- Конденсаторы.
- Макетная плата.
- Соединительные провода.
- Источник питания 12V.
Реклама: ООО "АЛИБАБА.КОМ (РУ)" ИНН: 7703380158
Датчик тока ACS712
Ключевым компонентом нашего проекта цифрового амперметра является датчик тока ACS712 от компании Allegro. Точное измерение тока во многих случаях является достаточно непростой задачей из-за влияния различных нежелательных шумов, однако датчик ACS712 значительно уменьшает проблемы измерения силы тока.
Принцип действия датчика основан на эффекте Холла, открытого ученым Эдвином Холлом. В соответствии с данным принципом когда проводник с током помещается в магнитное поле, на его концах, перпендикулярных направлению протекающего тока и направлению действия магнитного поля, генерируется напряжение. Данный принцип показан на следующем рисунке.
Для определения силы протекающего тока нам необходимо измерить величину магнитного поля (напряжения) вокруг проводника с током. Это напряжение называется напряжением Холла, его величина пропорциональна силе протекающего тока и составляет единицы милливольт.
Одним из основных достоинств датчика тока ACS712 является то, что он может измерять силу как переменного, так и постоянного тока и также обеспечивает развязку (изоляцию) между нагрузкой (постоянного или переменного тока) и измерительным блоком. Внешний вид датчика тока показан на следующем рисунке.
Как можно видеть из представленного тока, датчик содержит три контакта: Vcc, Vout и Ground. 2-х пиновый блок контактов предназначен для подключения проводников, прохождение тока через которые будет измеряться. Датчик работает от напряжения +5V, поэтому его контакт Vcc необходимо подключить 5V, а его контакт ground должен быть подключен к общему проводу схемы. На контакт Vout датчика подается сдвиг напряжения 2500mV, то есть если через датчик не протекает никакой ток, то напряжение на его выходном контакте будет равно 2500mV. Когда протекающий ток будет положителен, это напряжение будет больше 2500mV, а когда отрицателен – напряжение будет меньше 2500mV.
Для считывания напряжения с выходного контакта датчика тока мы будем использовать модуль АЦП микроконтроллера PIC. То есть когда на выходе данного АЦП будет значение 512 (соответствует напряжению 2500mV), это будет означать что через датчик ток не протекает. Значение на выходе АЦП будет уменьшаться если ток будет протекать в отрицательном направлении и увеличиваться, если ток будет протекать в положительном направлении. В следующей таблице показано соответствие между величиной протекающего через датчик тока и значением на выходе АЦП.
Эти значения можно рассчитать на основе информации, содержащейся в даташите на датчик тока ACS712. Их можно рассчитать по следующей формуле:
Vout Voltage(mV) = (ADC Value/ 1023)*5000
Current Through the Wire (A) = (Vout(mv)-2500)/185
Схема проекта
Схема амперметра на микроконтроллере PIC и датчике тока ACS712 представлена на следующем рисунке.
Схема запитывается от стабилизированного напряжения +5V, получаемого с выхода регулятора напряжения 7805. Для отображения значения тока будет использоваться ЖК дисплей 16х2. Выходной контакт датчика тока подключен к 7-му контакту микроконтроллера PIC, который также имеет обозначение AN4.
Схема соединений проекта приведена в следующей таблице.
№ п/п | № контакта микроконтроллера | Название контакта микроконтроллера | Куда подключен |
1 | 21 | RD2 | RS of LCD |
2 | 22 | RD3 | E of LCD |
3 | 27 | RD4 | D4 of LCD |
4 | 28 | RD5 | D5 of LCD |
5 | 29 | RD6 | D6 of LCD |
6 | 30 | RD7 | D7 of LCD |
7 | 7 | AN4 | контакт Vout датчика тока |
Вы можете собрать схему проекта на макетной или перфорированной плате, мы использовали для этой цели перфорированную плату из проекта мигания светодиодом на микроконтроллере PIC, внешний вид которой показан на следующем рисунке.
Моделирование работы проекта
Перед тем как собирать схему проекта в "реальном железе", ее работу можно проверить в симуляторе Proteus. Hex файл программы проекта для этой проверки можно скачать по следующей ссылке. Смоделированная в симуляторе Proteus схема проекта приведена на рисунке ниже. Измеренные значения тока в этой симуляции отображаются на экране ЖК дисплея 16х2. В качестве нагрузки переменного тока мы использовали лампу, в симуляторе можно достаточно просто изменять сопротивление данной лампы – в соответствии с ним будет изменяться и величина протекающего через нее тока.
Как видно из представленного рисунка амперметр показывает величину тока, протекающего через лампу, равную 3.52 A, а на ЖК дисплее показывается что величина тока равна 3.6A. На практике ошибка в определении тока может составлять до 0.2A. Для лучшего понимания работы схемы на экран ЖК дисплея также выводится значение на выходе АЦП и напряжение на его входе (в mV).
Объяснение программы для микроконтроллера PIC
Полный код программы приведен в конце статьи, здесь же мы кратко рассмотрим его основные фрагменты. Основным элементом нашей программы будет использование модуля АЦП микроконтроллера PIC, работу с которым мы более подробно рассматривали в этой статье.
Поскольку значение, считываемое с датчика тока, будет не совсем точным из-за того что ток переменный и подвержен влиянию шумов, для повышения точности результата мы будем считывать значение с АЦП 20 раз и усреднять его. Для расчета силы тока мы использовали формулу, приведенную ранее в статье.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
for (int i=0; i<20;i++) //Read value for 20 Times { adc=0; adc=ADC_Read(4); //Read ADC Voltage = adc*4.8828; //Calculate the Voltage if (Voltage>=2500) //If the current is positive Amps += ((Voltage-2500)/18.5); else if (Voltage<=2500) //If the current is negative Amps += ((2500-Voltage)/18.5); } Amps/=20; //Average the value that was read for 20 times |
Поскольку в данном проекте мы можем измерять силу переменного тока, то протекающий через датчик ток может быть как положительным, так и отрицательным. В этом случае значение напряжения на выходном контакте датчика может становиться как меньше, так и больше величины 2500mV. Поэтому в зависимости от того, положительным или отрицательным будет ток, необходимо использовать одну из двух формул для его расчета как показано в следующем фрагменте кода.
1 2 3 4 5 |
if (Voltage>=2500) //If the current is positive Amps += ((Voltage-2500)/18.5); else if (Voltage<=2500) //If the current is negative Amps += ((2500-Voltage)/18.5); |
Использование датчика тока на 30A
Если вам необходимо измерять ток силой более чем 5A, то в этом случае вы может купить модификацию датчика тока под названием ACS712-30A. Его подключение в схему будет таким же, как и датчика тока на 5A. В этом случае вам необходимо будет немного модифицировать программу проекта, заменив в ней значения 18.5 на 0.66 как показано в следующем фрагменте кода.
1 2 3 4 5 |
if (Voltage>=2500) //If the current is positive Amps += ((Voltage-2500)/0.66); else if (Voltage<=2500) //If the current is negative Amps += ((2500-Voltage)/0.66); |
Если вам необходимо измерять небольшие силы тока, то рекомендуем присмотреться к проекту амперметра на основе микроконтроллера AVR, который позволяет измерять ток величиной до 100mA.
Тестирование работы проекта
После того как вы соберете аппаратную часть проекта, загрузите программу в микроконтроллер PIC и подадите на схему питания, вы на экране ЖК дисплея должны увидеть значение силы тока, протекающего через проводник, подключенный к датчику тока.
Примечание: если вы используете датчик тока ASC7125A, убедитесь в том, что ваша нагрузка не потребляет ток более 5A, иначе используйте более толстые провода для ее подключения.
Более подробно работу проекта вы можете посмотреть на видео, приведенном в конце статьи.
Исходный код программы
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 |
/* Digital Ammeter for PIC16F877A * Code by: B.Aswinth Raj * Dated: 27-07-2017 * More details at: www.CircuitDigest.com */ #define _XTAL_FREQ 20000000 #define RS RD2 #define EN RD3 #define D4 RD4 #define D5 RD5 #define D6 RD6 #define D7 RD7 #include <xc.h> #pragma config FOSC = HS // Oscillator Selection bits (HS oscillator) #pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled) #pragma config PWRTE = ON // Power-up Timer Enable bit (PWRT enabled) #pragma config BOREN = ON // Brown-out Reset Enable bit (BOR enabled) #pragma config LVP = OFF // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming) #pragma config CPD = OFF // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off) #pragma config WRT = OFF // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control) #pragma config CP = OFF // Flash Program Memory Code Protection bit (Code protection off) //LCD Functions Developed by Circuit Digest. void Lcd_SetBit(char data_bit) //Based on the Hex value Set the Bits of the Data Lines { if(data_bit& 1) D4 = 1; else D4 = 0; if(data_bit& 2) D5 = 1; else D5 = 0; if(data_bit& 4) D6 = 1; else D6 = 0; if(data_bit& 8) D7 = 1; else D7 = 0; } void Lcd_Cmd(char a) { RS = 0; Lcd_SetBit(a); //Incoming Hex value EN = 1; __delay_ms(4); EN = 0; } void Lcd_Clear() { Lcd_Cmd(0); //очищаем экран ЖК дисплея Lcd_Cmd(1); //перемещаем курсор на 1-ю позицию } void Lcd_Set_Cursor(char a, char b) { char temp,z,y; if(a== 1) { temp = 0x80 + b - 1; //80H is used to move the curser z = temp>>4; //младшие 8 бит y = temp & 0x0F; //старшие 8 бит Lcd_Cmd(z); //устанавливаем строку Lcd_Cmd(y); //устанавливаем столбец } else if(a== 2) { temp = 0xC0 + b - 1; z = temp>>4; // младшие 8 бит y = temp & 0x0F; // старшие 8 бит Lcd_Cmd(z); // устанавливаем строку Lcd_Cmd(y); // устанавливаем столбец } } void Lcd_Start() { Lcd_SetBit(0x00); for(int i=1065244; i<=0; i--) NOP(); Lcd_Cmd(0x03); __delay_ms(5); Lcd_Cmd(0x03); __delay_ms(11); Lcd_Cmd(0x03); Lcd_Cmd(0x02); //02H is used for Return home -> Clears the RAM and initializes the LCD Lcd_Cmd(0x02); //02H is used for Return home -> Clears the RAM and initializes the LCD Lcd_Cmd(0x08); //Select Row 1 Lcd_Cmd(0x00); //Clear Row 1 Display Lcd_Cmd(0x0C); //Select Row 2 Lcd_Cmd(0x00); //Clear Row 2 Display Lcd_Cmd(0x06); } void Lcd_Print_Char(char data) //передаем 8 бит в 4-битном режиме { char Lower_Nibble,Upper_Nibble; Lower_Nibble = data&0x0F; Upper_Nibble = data&0xF0; RS = 1; // => RS = 1 Lcd_SetBit(Upper_Nibble>>4); //Send upper half by shifting by 4 EN = 1; for(int i=2130483; i<=0; i--) NOP(); EN = 0; Lcd_SetBit(Lower_Nibble); //Send Lower half EN = 1; for(int i=2130483; i<=0; i--) NOP(); EN = 0; } void Lcd_Print_String(char *a) { int i; for(i=0;a[i]!='\0';i++) Lcd_Print_Char(a[i]); //разделяем строку на отдельные символы с помощью указателей и передаем каждый символ по отдельности } /*****End of LCD Functions*****/ //**функции для работы с АЦП***// void ADC_Initialize() { ADCON0 = 0b01000001; //ADC ON and Fosc/16 is selected (включаем АЦП и выбираем частоту Fosc/16) ADCON1 = 0b11000000; // будем использовать внутреннее опорное напряжение } unsigned int ADC_Read(unsigned char channel) { ADCON0 &= 0x11000101; //Clearing the Channel Selection Bits ADCON0 |= channel<<3; //Setting the required Bits __delay_ms(2); //Acquisition time to charge hold capacitor GO_nDONE = 1; //Initializes A/D Conversion (старт АЦП) while(GO_nDONE); //ждем пока процесс АЦП не завершится return ((ADRESH<<8)+ADRESL); //возвращаем результат АЦП } //***End of ADC Functions***// int main() { int adc=0; //переменная, в которой будет храниться значение с выхода АЦП int a1,a2,a3,a4; //переменные чтобы разделить значение с АЦП на отдельные символы int Voltage; //переменная для хранения значения напряжения int vl1,vl2,vl3,vl4; // переменные чтобы разделить значение напряжения на отдельные символы int Amps; //переменная для хранения значения тока int Am1,Am2,Am3,Am4; // переменные чтобы разделить значение тока на отдельные символы TRISD = 0x00; //контакты PORTD будут работать на вывод данных – к ним подключен ЖК дисплей TRISA4 =1; //контакт AN4 будет работать на ввод данных ADC_Initialize(); Lcd_Start(); Lcd_Clear(); while(1) { /***Current Calculation*****/ for (int i=0; i<20;i++) //считываем значения 20 раз { adc=0; adc=ADC_Read(4); //считываем значение с АЦП Voltage = adc*4.8828; //рассчитываем значение напряжения if (Voltage>=2500) //если ток положительный Amps += ((Voltage-2500)/18.5); else if (Voltage<=2500) // если ток отрицательный Amps += ((2500-Voltage)/18.5); } Amps/=20; //усредняем считанные 20 значений /******Current Calculation******/ //**отображаем значение тока**// Am1 = (Amps/100)%10; Am2 = (Amps/10)%10; Am3 = (Amps/1)%10; Lcd_Set_Cursor(1,1); Lcd_Print_String("Current: "); Lcd_Print_Char(Am1+'0'); Lcd_Print_Char(Am2+'0'); Lcd_Print_Char('.'); Lcd_Print_Char(Am3+'0'); //**отображаем значение с выхода АЦП**// a1 = (adc/1000)%10; a2 = (adc/100)%10; a3 = (adc/10)%10; a4 = (adc/1)%10; Lcd_Set_Cursor(2,1); Lcd_Print_String("ADC:"); Lcd_Print_Char(a1+'0'); Lcd_Print_Char(a2+'0'); Lcd_Print_Char(a3+'0'); Lcd_Print_Char(a4+'0'); //**отображаем значение напряжения**// vl1 = (Voltage/1000)%10; vl2 = (Voltage/100)%10; vl3 = (Voltage/10)%10; vl4 = (Voltage/1)%10; Lcd_Print_String(" V:"); Lcd_Print_Char(vl1+'0'); Lcd_Print_Char(vl2+'0'); Lcd_Print_Char(vl3+'0'); Lcd_Print_Char(vl4+'0'); } return 0; } |