реклама на сайте
подробности

 
 
> Светодиодиодна индикация на PIC18F6722, Как правильно написать программу?
Andbiz
сообщение Aug 16 2012, 16:40
Сообщение #1


Местный
***

Группа: Свой
Сообщений: 447
Регистрация: 16-11-08
Из: Украина, Донецк
Пользователь №: 41 684



Здравствуйте, уважаемые форумчане!
Пробую освоить микроконтроллер PIC18F6722. Программа для работы – MPLAB IDE v8.86 + компилятор С18. Программатор – MPLAB ICD3. Есть плата, на которой уже установлен данный микроконтроллер и есть светодиоды, которые можно «позажигать», чтобы немного разобраться в работе данного МК.

Вот схемы платы:
Прикрепленное изображение

Прикрепленное изображение

Прикрепленное изображение


Микроконтроллер показан на третьей схеме.
Кварц стоит внешний – на 6 Мгц. Также используется внешний сторожевой ждущий таймер ADM706, который подключен к выводу 2 (RE0), которым нужно периодически давать импульсы, чтобы сбрасывать данный таймер и он не подал сигнал на перезапуск МК (я так понимаю).

На плате есть 8 семисегментных индикаторов HL1-HL8 (KingsBright SA56-11EWA).
Я решил написать программу, при которой на них будет написаны числа 12345678.
Сигналы на выбора сегмента (D0-D7) подключены от МК к индикатору через буферный регистр хранения информации ЭКФ1533ИР22. Сигналы на разрешение включения индикатора LE4 – LE11 подаются на индикатор с того же буферного регистра ЭКФ1533ИР22, на который данные сигналы подаются с МК через дешифратор ЭКФ1533ИД7 и инвертор сигналов ЭКФ1533ЛН1. С данными микросхемами я разобрался и написал для себя таблицу значений выходов МК, при которой будет зажигаться необходимая мне комбинация цифр.

Текст программы написал следующий:

Код
#include <p18f6722.h>

#pragma config OSC = XT // Применяю внешний кварцевый резонатор
#pragma config WDT = OFF // Внутренний сторожевой таймер отключаю - применяется внешний, который нужно периодически обнулять

void main (void)
{
    TRISD = 0;
    TRISE = 0;

    PORTD = 0; // Сбрасываю значения на порте D
    PORTE = 0; // Сбрасываю значения на порте E
    
    PORTD = 0xF9; // Принимаю соответствующие значения сегментов для индикатора HL1
    PORTE = 0x3; // Разрешаю индикацию индикатора HL1

    PORTD = 0xA4; // Принимаю соответствующие значения сегментов для индикатора HL2
    PORTE = 0x4; // Разрешаю индикацию индикатора HL2

    PORTD = 0xB0; // Принимаю соответствующие значения сегментов для индикатора HL3
    PORTE = 0x5; // Разрешаю индикацию индикатора HL3

    PORTD = 0x99; // Принимаю соответствующие значения сегментов для индикатора HL4
    PORTE = 0x6; // Разрешаю индикацию индикатора HL4

    PORTD = 0x92; // Принимаю соответствующие значения сегментов для индикатора HL5
    PORTE = 0x7; // Разрешаю индикацию индикатора HL5

    PORTD = 0x82; // Принимаю соответствующие значения сегментов для индикатора HL6
    PORTE = 0x8; // Разрешаю индикацию индикатора HL6

    PORTD = 0xF8; // Принимаю соответствующие значения сегментов для индикатора HL7
    PORTE = 0x9; // Разрешаю индикацию индикатора HL7

    PORTD = 0x80; // Принимаю соответствующие значения сегментов для индикатора HL8
    PORTE = 0xA; // Разрешаю индикацию индикатора HL8
    
    while (1); // Организую бесконечный цикл, для того, чтобы индикация светодиодов была постоянной
}


Программу скомпилировал, все прошло нормально, но прошивать МК еще не стал – решил спросить совета. Как я понимаю, при данной программе на мгновение должна появиться комбинация 12345678, т.к. с вывод микроконтроллера RE0 сигнал подается на ждущий таймер и индикаторы. Данный вывод у меня будет задействован в индикации и будет периодически менять свое значение, т.е. будет сбрасываться. Правильно ли я думаю? Правильно ли я написал программу? Правильно ли я указал конфигурационные биты в начале программы?
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов
Andbiz
сообщение Aug 22 2012, 17:01
Сообщение #2


Местный
***

Группа: Свой
Сообщений: 447
Регистрация: 16-11-08
Из: Украина, Донецк
Пользователь №: 41 684



_Артём_
Спасибо, понял – более компактный код можно достичь организацией матрицы, ее заполнением, а затем выводом элементов матрицы поочередно на индикаторы организацией цикла. #define – объявляет константы

esaulenka
Про более компактные комментарии понял.
Книгой Шпак «Программирование на языке С для AVR и PIC микроконтроллеров» пользовался и ранее, но только за 2011 год.
Да, с вольтметром ошибся – должен применяться АЦП. И ошибся с подключением ножек AVDD и AVSS – на самом деле они подключены к VDD и VSS. На принципиальной схеме не показаны, а на плате дорожки проведены под микросхемой и можно только определить, прозвонив прибором. Т.е. как я понял – вольтметр все же можно организовать. По поводу точности 0,01 – она на самом деле не сильно важна. Тут только учебные цели и погрешность условная. Пусть будет точность 5% - это не принципиально.

Попробую все же разобраться с вольтметром. В качестве аналогового входа для измерения напряжения, попробую использовать AN5. Выводы AVDD и AVSS подключены к +5В и GND.
В регистре ADCON1 в битах 5-4 с значениями 00 в качестве A/D VREF+ используется AVDD, а в качестве A/D VREF- используется AVSS. Т.е. как Вы и написали – по умолчанию опорными являются AVDD и AVSS (страница 272 даташита).
Т.к. опорное напряжение равно 5 В, то дискретность измерения АЦП будет равняться 5/1024 В =0, 00489 В/квант.
Т.к. АЦП будет оцифровывать напряжение от GND до AVDD, т.е. до 5 В. На всякий случай буду подавать напряжение на аналоговый вход AN5 через делитель по следующей схеме:
Резистор R2 для защиты входа МК, падением напряжения на нем принебрегаю ввиду малости тока АЦП. На резисторе R1 падение напряжения 1,65 В, поэтому максимально подаваемое напряжение на АЦП равно 3,35 В – при этом значении на входе будет 5 В и это значение нужно будет отобразить на семисегментном индикаторе. При уменьшении напряжения значение на индикаторе должно соответственно уменьшаться.

Прикрепленное изображение


Код
return ( ADRESL + ( ADRESH << 8 ) ) * 0.00489;

В работе АЦП есть такая строка. Return возвращает результат АЦП в необходимый кусок программы с необходимым значением. При этом происходит доумножение результата на 0,0489 (дискретность измерения), т.е. узнают величину напряжения в десятичной форме.
Вопросы по этой строке:
1) За return должно следовать выражение в скобках, которое может выполняться и переноситься в необходимый участок схемы. В данном случае в скобки берётся не все выражение, а только часть. Т.е. скобки ставить не обязательно и так можно делать?
2) Знак << 8 означает поразрядный сдвиг влево на 8 разрядов. Для чего это делать. Затем эти два разряда складывают. Зачем это делать?

Пока программа выглядит таким образом:

Код
#include <p18f6722.h>

#pragma config OSC = XT        // Применяю внешний кварцевый резонатор
#pragma config WDT = OFF    // Внутренний сторожевой таймер отключаю - применяется внешний, который нужно периодически обнулять сигналом ADR0

void IzmerVoltage (void)
{
    ADCON0bits.GO=1; //запускаю преобразователь АЦП, записав 1 в бит1 регистра ADCON0
    while (ADCON0bits.GO==1); //запускается цикл проверки работы АЦП. Окончание преобразование - окончание цикла
    return ((ADRESL+(ADRESH<<8))*0.00489);    
}

void main void    //точка входа в основную програму
{
    ADCON0=0x15;    //разрешаю работу АЦП (бит0=1), выбираю входа AN5 (биты2-5=0101)
    ADCON1=0x09;    //AN5-аналоговый вход (биты0-3=1001), AVDD и AVSS - опорные (биты4-5=00)
    ADCON2=0x8C;    //частота работы АЦП=1,5Мгц (биты0-2=100), время 2*Tad (биты3-5=001), результат АЦП justifield справа(бит7=1)
    
    TRISF=1;            //порт F - вход
    
    while (1)
    {
    
    Тут будет программа

    }
}


Каким образом лучше сделать соответствие между измеренным значением напряжения с АЦП в десятичной форме и индикаторами? Т.е. каким образом можно привязать целую часть и дробную часть числа к отдельным индикатором и выводить на нее необходимую комбинацию сегментов?
Go to the top of the page
 
+Quote Post
Ruslan1
сообщение Aug 23 2012, 08:54
Сообщение #3


Гуру
******

Группа: Свой
Сообщений: 2 360
Регистрация: 6-03-06
Из: Кишинев
Пользователь №: 15 025



Про индикацию:
самое простое для разборок- это
1. вычислить значение в вольтах или в тех единицах вольт, которые нужно отобразить. Это позволяет остаться в границах целочисленной арифметики. Например, делаем все в милливольтах. Тогда 16-битного целого хватит для напряжений до 65.535 В.
Код
Umv = ( UREFmV / (1<<NADC) * ADCcode) * KATT

где
UREFmV = 5000 (mV)
NADC - разрядность АЦП (у Вас это 10)
ADCcode - код прочитанный из АЦП
KATT - коэффициент ослабления аттенюатора (делителя) на входе. в Вашем случае 1.

2. переводим эту величину в посимвольное отображение в буфере
Код
char buf[5+1];  // максимальная отображаемая величина требует 5 знакомест плюс символ конца строки 0x00 в конце
sprintf (buf, "05d", Umv);

после этого число Umv будет "напечатано" в буфер buf, причем старшие незначащие цифры будут '0'. например, величина 1234 будет напечатана как "01234"

3. добавляем десятичную точку в буфер. Это позволяет дальше удобно и без хитростей выводить подготовленный буфер куда угодно.
Код
char buf2[2+1+3+1];  // 2 на целую часть, 1 на точку, 3 на дробную часть, 1 на завершающий строку символ
buf2[0]= buf[0];
buf2[1]= buf[1];
buf2[2]= '.';
buf2[3]= buf[2];
buf2[4]= buf[3];
buf2[5]= buf[4];
buf2[6]= '\0';

3. Выбираем посимвольно из буфера цифры и делаем с ними все что хотим например:

Код
const char IND_ADDR[] = {NULL, ADDR_HL1,ADDR_HL2,ADDR_HL3,};   // нулевой элемент массива не используется
for (i = 1 to 6)
{
switch (buf2[i])
{
  case '.': out = LED_CODE_DOT; break;
  case '0': out = LED_CODE_0; break;
  case '1': out = LED_CODE_1; break;
  case '2': out = LED_CODE_2; break;
  case '3': out = LED_CODE_3; break;
  default: out = LED_CODE_E; break;  // error
} // end switch()
Indicator(IND_ADDR[i], out);
}; // end for()


Я конечно помню, что всякие АЛС324 одновременно с символом могут точку светить в этом же разряде, но это уже следующий этап игры sm.gif
Go to the top of the page
 
+Quote Post

Сообщений в этой теме
- Andbiz   Светодиодиодна индикация на PIC18F6722   Aug 16 2012, 16:40
- - Andbiz   Программу записал в МК. В результате получилась сл...   Aug 17 2012, 17:29
|- - Ruslan1   на ИР22 (SN74LS373) остаются (хранятся) те данные,...   Aug 17 2012, 19:53
- - ILYAUL   Цитата1. Коментарии должны быть полезны, а не прос...   Aug 17 2012, 20:14
- - Andbiz   Большое спасибо за помощь! Цитатана ИР22 (SN7...   Aug 20 2012, 15:28
|- - Ruslan1   Цитата(Andbiz @ Aug 20 2012, 18:28) Я обр...   Aug 20 2012, 17:20
- - Andbiz   Сигнал LE1 идет на микросхему D7 ЭКФ1533ИР22 (перв...   Aug 20 2012, 17:52
- - Andbiz   Написал другую программу. Предприятие, на котором ...   Aug 21 2012, 15:40
|- - _Артём_   Цитата(Andbiz @ Aug 21 2012, 18:40) Прогр...   Aug 21 2012, 15:55
- - esaulenka   Маленький совет: при написании комментариев забыть...   Aug 21 2012, 16:28
|- - _Артём_   Цитата(esaulenka @ Aug 21 2012, 19:28) Ма...   Aug 21 2012, 16:36
- - _Ivana   Да, читая комментарии я только ещё больше путаюсь ...   Aug 21 2012, 16:43
- - esaulenka   и о ЦАПах, которые на самом деле очень даже АЦП Ц...   Aug 21 2012, 17:23
- - esaulenka   Цитата1) За return должно следовать выражение в ск...   Aug 23 2012, 11:46
- - Andbiz   Спасибо! Программу сделал. Код получился следу...   Aug 31 2012, 18:51
- - Andbiz   Программу для ввода текста сделал – вводит в...   Sep 5 2012, 14:15
- - Andbiz   Вопрос еще по поводу функции sprintf . Могу ли я и...   Sep 5 2012, 19:01
- - esaulenka   Вот зачем, интересно, мы тут кучу советов надавали...   Sep 6 2012, 11:26
|- - Andbiz   Цитата(esaulenka @ Sep 6 2012, 14:26) Вот...   Sep 6 2012, 14:50
- - esaulenka   ЦитатаПри нажатии клавиши может отобразиться много...   Sep 7 2012, 09:31


Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 26th August 2025 - 07:48
Рейтинг@Mail.ru


Страница сгенерированна за 0.01409 секунд с 7
ELECTRONIX ©2004-2016