Программирование PIC на С. Цифровой вольтметр с LCD 16x2.

PIC
В этой части смоделируем цифровой вольтметр постоянного тока на pic контроллере PIC16F676 с отображением результата измерений на 2-х строчном дисплее. На этом примере будет показана работа с АЦП, с подключаемыми драйверами, работа с ЖКИ.
Использован компилятор CCS PICC Compiler v4.120.

Несколько слов о дисплее. Дисплей такого плана:

wh1602

В Proteus его тип значится как LM016L.
Дисплей может работать по 8 ми, или по 4 х битной шине данных (задается при инициализации), т.е. будет использоваться 8 или 4 выводов контроллера для передачи данных. Мы будем работать по 4-х битной шине, при которой у дисплея используются выводы D4-D7.

С учетом этого, схема для проекта выглядит следующим образом:

Схема

Алгоритм работы прост – измеряем напряжение на выводах потенциометров и выводим его значение на дисплей.

Приступим к созданию проекта.
В этот раз напишем всю программу вручную.
Первая строка нашей программы будет
#include <pic16f676.h>
в которой мы подключили файл описания команд контроллера.
Далее нужно прописать фьюзы. Для этого переходим на вкладку View-Valid Fuses, выбираем в списке наш контроллер и смотрим доступные варианты.

Фьюзы

Об их назначении по описанию можно узнать из ДШ. Выберем источник тактовых импульсов – встроенный RC-генератор, отключим WD, PUT, Master Clear Enable pin — вывод сброса работает как вход/выход, BD.
#fuses INTRC, NOWDT, NOPUT, NOMCLR, BOWNOUT
Далее указываем частоту тактового генератора в Гц,
#use delay(clock=4000000)
Т.к. мы будем работать с АЦП, укажем его разрядность
#device ADC=10
Для работы с дисплеем подключаем соответствующий драйвер. Будем использовать не родной lcd.c а его упрощенную (в плане работы с ним) версию — flex_lcd.c. (есть в присоединенном архиве)
#include «flex_lcd.c».
Основная конфигурация настроена, размещаем блок главной программы:
void main()
{

}

Что бы дисплей заработал, ему нужно предать соответствующие команды. Таких команд много, и пока с ними всеми освоишься да пока их правильно запишешь – уйдет масса времени. Для облегчения нашей с вами жизни добрые люди написали все нужные последовательности команд в кучу и оформили их в виде функций – небольших программок, которые делают конкретные действия, например, перемещают курсор в нужную позицию. И все эти функции собирают в одном файле, который нам надо всего-то прикрепить командой (директивой) #include <> к нашему проекту. Ну и изучить его, что там в нем за функции и как с ними работать.

Открываем flex_lcd.c блокнотом и первое что видим – присвоение выводам дисплея выводов котроллера. Подправим их на свой лад. Например, чтоб подключить вывод дисплея к выводу А0, правим строку
#define LCD_RS PIN_A0
Если работать с дисплеем только на вывод данных, вывод RW можно не присоединять, а просто заземлить. Тогда нужно закомментировать строку
#define USE_LCD_RW 1
Больше ничего изменять не нужно. Сохраните изменения.
Рассмотрим доступные функции.
Прежде чем что либо сделать с дисплеем, нужно вызвать функцию инициализации — lcd_init().
lcd_gotoxy(x,y) – переход курсора на позцию x,y. Самая левая вехняя – 1.1.
lcd_putc(char c) – вывод символов. Дополнительные параметры
\a установка курсора левее на позицию
\f очистить дисплей и курсор вверх влево
\n переход на вторую линию
\b назад на 1 позицию
Это основные команды работы с дисплеем. Выведем на дисплей надпись we.easyelectronics.ru!

lcd_init(); 
lcd_putc("\fwe.easyelectroni\n"); 
lcd_putc("     cs.ru!"); 
for(;;)
{
}

for(;;) — еще один способ сделать бесконечный цикл, надо же как то занять контроллер (можно было бы его усыпить коммандой SLEEP(); но, дудки, пущай трудится!)
Вставим этот код в блок главной программы. Откомпилируем проект. На вкладке Compile щелкаем Compile. Запускаем Протеус и проверяем: все работает!

Проверяемс!

Разберемся с АЦП. Сначала нужно его настроить, затем произвести измерение, затем преобразовать из бинарного числа в десятичное и вывести на дисплей.
Открываем блокнотом pic16f676.h (он находится в C:\Program Files\PICC\Devices) и видим доступные функции и их параметры.

////////////////////////////////////////////////////////////////// ADC
// ADC Functions: SETUP_ADC(), SETUP_ADC_PORTS() (aka SETUP_PORT_A),
//                SET_ADC_CHANNEL(), READ_ADC()
// Constants used for SETUP_ADC() are:
#define ADC_OFF                0              // ADC Off
#define ADC_CLOCK_DIV_2    0x100
#define ADC_CLOCK_DIV_4     0x40
#define ADC_CLOCK_DIV_8     0x10
#define ADC_CLOCK_DIV_32    0x20
#define ADC_CLOCK_DIV_16    0x50
#define ADC_CLOCK_DIV_64    0x60
#define ADC_CLOCK_INTERNAL  0x30              // Internal 2-6us

// Constants used in SETUP_ADC_PORTS() are:
// First argument:
// OR together desired pins
#define sAN0                   1         //| A0
#define sAN1                   2         //| A1
#define sAN2                   4         //| A2 
#define sAN3                   8         //| A4 
#define sAN4                  16         //| C0
#define sAN5                  32         //| C1
#define sAN6                  64         //| C2
#define sAN7                  128        //| C3
#define NO_ANALOGS             0         // None
#define ALL_ANALOG            255        // A0 A1 A2 A4 C0 C1 C2 C3 

// Optional Second argument:
#define VSS_VDD              0x0000  // Range 0-Vdd
#define VSS_VREF             0x4000  // Range 0-VrefH

// Constants used in READ_ADC() are:
#define ADC_START_AND_READ     7   // This is the default if nothing is specified
#define ADC_START_ONLY         1
#define ADC_READ_ONLY          6

пишем код:
настраиваем время выборки и диапазон вхоного напряжения (0-5в)
setup_adc(ADC_CLOCK_INTERNAL|VSS_VDD);
устанавливаем аналоговым входом вывод А2
setup_adc_ports(sAN2);
выбираем канал АЦП для считывания
set_adc_channel(2);
АЦП настроен. Оцифрованное значение надо куда-то сохранить, для этого объявим шестнадцати разрядную переменную целого типа adc_value беззнакового типа. Для этого допишем в начале главной программы
int16 adc_value;
Что б правильно отобразить на дисплее измеренное напряжение нужно преобразовать считанное значение:
adc_value = read_adc();
volts = (float)adc_value*5/1023;

Для сохранения результата введена новая переменная volts вещественного типа.
Наш АЦП 10 битный, т.е.максимальное цифровое значение на его выходе 2^10-1=1023, что соответствует максимальному входному напряжению – 5в. 5/1023, это коэффициент пересчета, что б перевести цифровое значение к аналоговому.
Осталось вывести на дисплей результат:
printf(lcd_putc, "\fU=%3.2f V", volts);
"\fU=%3.2f V", volts – очищаем дисплей, выводим U= нашу переменную volts (3.2f – формат вывода) и буковку V.
Полная программа:

#include  <16F676.h>  
#fuses NOMCLR, INTRC, NOWDT, NOPUT, NOPROTECT, NOBROWNOUT
#device ADC=10             
#use delay(clock=4000000)  
#include "flex_lcd.c" 

 void main() 
 { 
int16 adc_value; 
float volts;

lcd_init(); 
 
//lcd_putc("\fwe.easyelectroni\n"); 
//lcd_putc("     cs.ru!"); 
setup_adc(ADC_CLOCK_INTERNAL|VSS_VDD);
setup_adc_ports(sAN2);
set_adc_channel(2);

for(;;)
{
    adc_value = read_adc(); 
   volts = (float)adc_value*5/1023;    
    printf(lcd_putc, "\fU=%3.2f V", volts); 
    delay_ms(500);
}
 }


в ней вы видите закомментированные строки
//lcd_putc("\fwe.easyelectroni\n");
//lcd_putc(" cs.ru!");
это сделано с целью экономии памяти контроллера, т.к. с ними выскакивает ошибка о ее нехватке. Без них память загружена на 95%.

Компилируем, загоняем в Протеус и наслаждаемся результатом:

Ура! Получилось!

В прикрепленном архвиве все файлы для проекта.

UPD UPD UPD

применение ресурсоемких типов float и команды printf хоть и дает самую высокую точнось измерений, но съедает более 60% памяти, весьма немало.
Уменьшить размер программы можно пожертвовав точностью (хотя, врятли есть смысл держать ее на таком уровне) отказавшись от float и организовав вывод данных на дисплей не через printf. Вариант программы от grand1987:

void main(void)
{
int16 volts; // вводим переменные
int16 adc_value;
 
setup_adc(ADC_CLOCK_INTERNAL|VSS_VDD); //настраиваем АЦП
setup_adc_ports(sAN2);
set_adc_channel(2);

lcd_init();                   //ициализируем АЦП
lcd_putc("\fDIGITAL\n");      //рюшечка :)
lcd_putc("VOLTMETER ON PIC"); 
delay_ms(1000);
while(1)
{
  lcd_putc("\fU=");             //очистка дисплея, вывод U=
  adc_value = read_adc();       // считываем значение с АЦП
  volts = (adc_value*49)/10;    // преводим в милливольты
  lcd_putc((volts/1000)+'0');   // выводим тысячи миливольт
  lcd_putc('.');
  lcd_putc(((volts/100)%10)+'0');  // выводим сотни миливольт
  lcd_putc(((volts/10)%10)+'0');   // выводим десятки миливольт
  lcd_putc("V");                   //вывод V
  delay_ms(500);                   
 }
}

c учетом всех рюшечек, программа умешьилась с 95 до 52%, т.е. почти в 2 раза.
За что grand1987 уважение и почет. Результат:



АП: в комментариях обещался выложить фото своего первого программатора. Рылся недавно в ящике, вот он:
RCD programmer
называется RCD programmer, схема легко нагугливается, приводить не буду. Программа для прошивки — WinPIC800. Работал через СОМ.
  • +1
  • 02 июня 2011, 10:04
  • Flash
  • 1
Файлы в топике: Voltmetr_PICC.zip

Комментарии (82)

RSS свернуть / развернуть
Выюзать всю память МК программой на пару десятков строк… :) 1К слов — не так мало, аналог 2кб на AVR.
0
  • avatar
  • Vga
  • 02 июня 2011, 11:45
"\fwe.easyelectroni\n"
"     cs.ru!"

а незя как нить строки во флеш запихнуть?

#fuses
#device
#use delay

facepalm.jpg
0
точнее,
#facepalm.jpg
:)
0
Ну считай что это #pragma(fuses, ...) :) А вот float и printf — это жестоко.
0
Точно, жестоко! Потому и размер такой получился!
0
Ну считай что это #pragma(fuses, ...) :) А вот float и printf — это жестоко.
а как можно улучшить? действитльно, их доля более 60% :(
0
Потыкать разработчиков этого «компилятора» носом в их синтаксис и прочитать лекцию на тему «что такое препроцессор в Си».
0
А вместо float'ов юзать fixedpoint. :)
0
Можно подумать, прагмы читает препроцессор. А тут местами инфа вообще для программатора (фьюзы например).
0
Прагмы это инструкции компилятору. Фузы к ним явно не относятся.
0
Но они же имеют синтаксис команд препроцессора. А тут — команды компилятору, линкеру, погроматору, в том же синтаксисе. Зато все фузы в проекте, а не
— Я прошил прошивку, а оно по кнопке сбрасывается, а не мигает!
— А ты фуз RSTDSBL установил?

Но эти хотя бы в других компилерах не скомпиляцо. А вот в хелпе SDCC (таргет С51) прямо сказано — Keil'овская (и вроде IAR'овская тоже) конструкция sbit REGNAME ^ BITNUM будет скомпилена без синтаксических ошибок как xor. Кстати, так и не нашел в SDCC метода объявить байтик в bdata и затем — несколько бит в нем как переменные.
0
Выюзать всю память МК программой на пару десятков строк… :) 1К слов — не так мало, аналог 2кб на AVR.
это ж круто! вместо 1к комманд на асме всего 10 строк на Си! Даешь языки высокоуровневого программирования!
0
Хм, ты считаешь что на асме такая программка весила бы 1к?
Я думаю поменьше, раз в 20. :)
0
На С тоже. Если не использовать занимающие 95% вычисления с плавающей запятой и универсальный printf. Он полезен когда в программе десятки строк, куда нужно подставлять значения.
Впрочем, программа выполняет порученную задачу и укладывается в имеющиеся ресурсы. Значит — нормальная. Правда, расширять ее уже некуда)
0
Ну не факт. Скажем, бутлоадер для межки8 с поддержкой чтения/записи флеша/еепрома я так и не смог запихать в 256 байт на Си. Пришлось перебороть лень и написать на асме. :)
0
И сколько получалось на С? Алсо, поделись исходничками бута. По какому он интерфейсу робит?
0
вот. :)
Не помню уж скока на Си получалось.
0
На С тоже. Если не использовать занимающие 95% вычисления с
ну, не в 20. Если закомментить строки с float printf, программа занимает 20% против 95%. Но при этом не учитывается преобразование и вывод на дисплей, а это займет еще минимум 20%. Так что в 2 раза максимум можно упростить если кто нибудь покажет как
0
Ну написать свои рутины для отображения типов данных не так сложно.
Как-то мне достался проект на доработку, в котором printf тупо не помещался :).
А те функции вывода что там уже имелись, были ущербны. Пришлось писать заново.
Пока писал — пришлось переделывать основное ядро.
В итоге получилось так что после переработки кода стал вполне свободно влезать sprintf, без реализации float'а…
0
неа… это была попытка оправдаться :)
0
Хм, ты считаешь что на асме такая программка весила бы 1к?
Я думаю поменьше, раз в 20. :)
неа… это была попытка оправдаться :)
0
… раз уж работаеш с float то точнее будет
volts = ((float)adc_value*5)/1023;
+1
раз уж работаеш с float то точнее будет
volts = ((float)adc_value*5)/1023;
а в чем улучшиться точность? А
0
… 1023/5 = 204.6
+1
Действительно. Стал точнее. Буду редактировать…
0
volts = ((float)adc_value*5 + 1023/2)/1023;
если уж совсем по фен-шую. :)
0
А вот тут я уже не понимаю.
0
Упс. Я тоже. :/
0


Два килобайта на вольтметр — это сурово.

если кто нибудь покажет как

1. Не использовать сторонние библиотеки. Писать функции для работы с периферией самостоятельно и только те, которые нужны. Возможно, на асме.

2. Никаких вещественных чисел. Хотим точность два знака? Умножаем на 100 и действуем с целыми числами.

3.Никаких printf'ов. Пишем функции работы со строками ручками.

Ну и, конечно, никаких протеусов — только железо.

Это основное…
0
ну, для начала, не 2, а 0,97! :)
если все писать самостоятельно, сколько ж времени понадобится?
за второй пункт не понял, что умножаем на 100?
как без printf с меньшими затратами вывести на символьный дисплей число в бинарном коде?
покажите КАК. я вижу только слова
не в обиду, защиту ПИКов или еще с какой злой умыслью. Просто судить все мастера, а сделать… да и интересно, как по другому решить. Я не нашел нигде.
0
0.97 Kw. Не помню только размер слова, он в диапазоне 12-16 бит. Т.е. 1.5-2кб. У AVR слово 16 бит, а память указывается в килобайтах, так что аналог этого чипа по размеру памяти какая-нить ATtiny26.
Вместо флоата можно сделать так: adc_value = (63 * adc_value) >> 7. Правда, будет несколько завышать, но погрешность менее 1%. Затем можно преобразовать в BCD и вывести <сотни>.<десятки><единицы>. Особенно удобно это на семисегментниках, где точка не требует отдельного знакоместа. Можно и преобразовывать в строку чем-то вроде atoi, она не столь страшна, как printf — но точку в строку придется добавить самому.
Библиотеку LCD можно оставить. Хотя они и правда обычно довольно тяжелые, но самописная врядли (намного) легче будет.
0
ну, это уже проблемы АВР, что у них вместо 1 — 2. :) ладно, это фигня, как уменьшить?
в том то и фича, что это не семисегментник, который бинарный код принимает, а символьник. и даже самый матерый прогер мнее чем в 0,6-0,7к не впишет вольтметр с LCD. imho
0
Нет-нет. Просто для пиков память программ указана не в байтах. Для PIC16F676 длина слова — 14 бит. Т.е. у него 1.75кб флэша, и из них занято 97%.
LCD — да, несмотря на, казалось бы, весьма простой код занимает порядка 150-200 слов. Это 15-20% памяти этого контроллера. Но поддержка float и printf отъедает процентов 70.
0
… вот мужик замутил амперметр + вольтметр + термометр на одной ATtiny13
0
надо посмотреть!
0
по сути, там один вольтметр.
0
программа занимает 1020 байт
0
еще бы с баскомом разобраться…
0
… попробуй этот код (щас сам его опробую на Attiny13)
int volts;

void main(void)
{
 // тут код со всякими инициализациями
 lcd_goto(1,6); // выводим один раз букву "V" и забываем о ней
 lcd_putc('V');
 while(1)
 {
  lcd_goto(1,0); // начинаем с ночала строки

  volts = ((adc_value*5)/1023)*1000; // результат в миливольтах
  lcd_putc((volts/1000)+'0'); // выводим тысячи миливольт
  lcd_putc('.');
  lcd_putc(((volts/100)%10)+'0'); // выводим сотни миливольт
  lcd_putc(((volts/10)%10)+'0'); // выводим десятки миливольт
  lcd_putc((volts%10)+'0'); //выводим единицы миливольт
  delay_ms(500);
 }
}

Убири float, printf() а из всех LCD функций оставь только lcd_putc() и lcd_goto(). Естественно в данном примере максимальный результат будет 9999мВ, для больших результатов добавляешь десятки тысячь миливольт и т.д.
+1
ок. сейчас попробую!
0
… хотел еще поставить
adc_value = read_adc();
перед
volts = ((adc_value*5)/1023)*1000; // результат в миливольтах

но походу ctrl+V выводит комент
0
для больших результатов добавляешь десятки тысячь миливольт и т.д.
сам себя поймал
… как минимум в AVR максимальное измеряемое напряжение равно VCC плюс минус копейки, так что четырех digit-ов хватит
0
Работает. 42%! Только так: во втором ряду 0.160 при 4,99 на входе. V нет.
0
а при 2,5 на входе на дисплее 0,208 :(
0
… а read_adc() значение какого типа возвращает?
… смести «V» правей
0
read_adc() считывает значение с ацп. возвращает значение в диапазоне 0-1023 (10 бит)
с V я разберусь, это мелочь (сдвиг не помогает)
показания «хаотичны», так, при 0,99 — 0.000, при 1,30 — 0,232
0
… кажись знаю, дело в:
volts = ((adc_value*5)/1023)*1000;
попробуй эту строчку, но точность чуть ухудшется
volts = (adc_value*49)/10;
+1
… приведи adc_value, volts и read_adc() к единому типу, лучше к unsigned int:
unsigned int adc_value, volts;
+1
приведи adc_value, volts и read_adc() к единому типу, лучше к unsigned int:
unsigned int adc_value, volts;

так показания 0.000 всегда
0
сделал int16. Правильно показывает вольты. Например, при 4.99 — 4.000, при 1.75 — 1.000
0
попробуй эту строчку, но точность чуть ухудшется
volts = (adc_value*49)/10;
— работает!
grand1987, снимаю шляпу! Погрешность единицы мв
0
память 46%
0
… даешь Си без границ!!! :))
0
Погрешность на верхнем пределе значений — 12мв.
В начале — 0.
0
… ошибка изза деления 5000/1023 = 4.88…, а в коде 49/10, отсюда и 12мВ
0
при 2,5 в погрешность около 3 мв, 1%, весьма замечательно. но ради спортивного интереса надо будет подумать, как ее убрать вообще.
0
я имел ввиду 0,1%!
0
… а если вот эта строчка:
volts = (adc_value*49)/10 - (adc_value%85);
0
… упс, вот ета:
volts = ((adc_value - (adc_value%85))*49)/10 - 1;
0
упс, вот ета:
volts = ((adc_value — (adc_value%85))*49)/10 — 1;
вверху — пара милливольт
до 0,5 — 15 мв
ниже 0,5 на месте единиц вольт какойто символ
0
добавил в статью новый вариант.
grand1987 — еще раз снимаю шляпу. Никаких пустых разговоров, все показал делом.
0
… лучше использовать
volts = (adc_value*49)/10 - (adc_value%85);
со вторым вариантом я перемудрил
0
… да и ты еще забыл про lcd_goto()
0
лучше использовать
volts = (adc_value*49)/10 — (adc_value%85);
с ней при 0,24 на входе 0,19 на выходе (и 53%).
… да и ты еще забыл про lcd_goto()
его применение не дало положительных результатов.
Вцелом, получился довольно не плохой проект, который можно использовать не только в образовательных целях, но и в реальных конструкциях.
0
… я все пишу, а сам код не испытал, поставил я вот такую строчку
volts = (data*49)/10 - (data%84);
… и получил максимальную погрешность 3мВ (при 5В), так что заказ исполнен — погрешность 0.06%, но не надо забывать что это симуляуия, да и сама аналого-цифровое преоброзование имеет свою погрешность, так что в реальности быдет больше.
0
… так что в принципе можно отображать и единицы миливольт
0
это получается как бы запас по точности.
Рельно, сколько паяю, точность измерения более 2-3 знаков не требовалась.
Можно использовать такую точность — замутить еще и амеперметр, а потом сделать по 2 канала V/I.
0
если все писать самостоятельно, сколько ж времени понадобится?

А Вам в спину дышит заказчик?

что умножаем на 100?

Значения, с которыми действуем. Впрочем, тут уже объяснили…

как без printf с меньшими затратами вывести на символьный дисплей число в бинарном коде?

Приведенная ниже функция преобразует число в его запись в цифирках и вставляет оную в переданную строку. Писано мной для термометра на MSP430 с выводом через UART (как раз чтобы не использовать sprintf), но, поскольку это С, должно работать где угодно.


/*
This function converts an integer value into its character
representation and stores these characters into 'numstr's
next 6 or 'NumDgt' (see note below) characters from 'StartPos'.

'num'       -   integer to convert to string;

'numstr'    -   target string;

'StartPos'  -   the next 6 characters from 'StartPos' will
                be used for storing 'num' characters. The best
                way is to fill them with spaces before calling
                PutIntToStrEx().
                NOTE:
                If 'NumDgt' is zero, function will always use
                exactly 6 characters.

'NumDgt'    -   Optional number of digits to convert to characters.
                If 'NumDgt' is not zero, only 'NumDgt' charaters
                will be converted and placed to 'numstr'. If 'num'
                has less digits than specified in 'NumDgt', leading
                zeroes will be added.
                NOTE:
                If 'num' is negative, function will use one extra
                character to store sign.
*/

void PutIntToStrEx(int num,char numstr[],int StartPos,char NumDgt)
{
    int i;
    char sign=' ';
    
    if (num<0)
    {
        num=-num;
        sign='-';
    }

    if (!NumDgt)
    {
        if (sign==' ')
            i=StartPos+5;
        else
            i=StartPos+6;

        do
        {
            --i;
            numstr[i]=(num % 10) | 0x30;
        }while (num/=10);

        --i;

        numstr[i]=sign;
    }
    else
    {
        if (sign==' ')
            i=StartPos+NumDgt;
        else
        {
            i=StartPos+NumDgt+1;
            numstr[StartPos]=sign;
            ++StartPos;
        }

        do
        {
            --i;
            numstr[i]=(num % 10) | 0x30;
            num/=10;
        }while (i>StartPos);
    }
}
0
А где фото готового изделия?
0
Так написано же, что в протеусе симулировали, нету изделия.
0
как спаяешь, так и выложим.
В этой части смоделируем цифровой вольтметр
первое предложение статьи.
0
а зачем экономить память, если мк больше ни для чего не используется?
0
Чтобы потом не набыдлокодить в более серьезном проекте =) Ресурсы-то не безграничны. К тому же в итоге это не только объем памяти, но и быстродействие. Ладно, когда ARM со всякими аппратными делителями, а на младших пиках даже умножителя h/w нету.
0
на счёт потом согласен. хотя второй уплотнённый вариант выглядит не так красиво. но вот на быстродействие это не повлияет точно, учитывая что в цикле стоит задержка на полсекунды.
0
Ну да, есть такое дело.
0
цель данной статьи — образовательная, поэтому, размер памяти, в принципе, не важен. главное понять суть — как и что делать. второй вариант программы оптимизированн по обьему памяти и работает немного по другому. что то же замечательный образовательный пример. решить одну и ту же задачу можно разными путями, какой выбрать путь — решать уже каждому самостоятельно, под свои цели.
0
Если добавить многократное измерение и выводить среднее то повышается устойчивость к помехам.
Вот пример кода, занимает памяти примерно столько же.

   for(;;)
   {
     adc_value = 0;
     int8 i;
     for (i = 49; i >0; --i)
     {
         adc_value += read_adc();// Сложение вместо умножения
         delay_ms(10);// Задержка между измерениями
     }
     volts = ( adc_value ) /10  - adc_value / 3969;   // Перевод в милливольты
     
     lcd_putc("\fU=");
     ... Вывод на LCD
     delay_ms(100);
   }

Когда то давненько пытался изучать PIC контролеры, но используемая модель памяти охоту отбила. Благодаря этой статье узнал о существовании нормального Си компилятора для них.
Решил спаять и проверить в железе. Пошел в магазин купить экран и контролер… а ещё купил STM8L-discovery. В результате — некогда спаять программатор для PIC-a. =)
0
возникнет ошибка если будет
int8 i; стоит применить int16.
некогда спаять программатор для PIC-a
— на выходных найду и сделаю фото первого прогера — rcd. На куске текстолита, полунавесом пара транзисторов, диодов, резисторов.
0
i — меняется от 0 до 49. Int8 хватает с запасом…
0
действительно, ступил, чегото
0
Добрый день. Я только разбираюсь с микроконтроллерами. При компиляции Вашего проекта выходит ошибка:
A #DEVICE required before this line

Жалуется на эту строку:
int8 const LCD_INIT_STRING[4] =

А что сюда нужно вписать?
0
Все, разобрался. Почистил проект, все работает. Спасибо.
0
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.