Перейти к содержанию

Помогите пожалуйста в написании исходного текста...


Гость химик

Рекомендуемые сообщения

Ну тогда помогайте, не буду сбивать с толку своим дилетантским подходом)

 

Да ладно... просто попробовать работу с RTC и LCD на самом деле лучше не отвлекаясь на дополнительные сложности, как в вашем примере. А в production уже стоит задуматься о грамотной организации структуры приложения. Я для production предложил поюзать прерывания.

 

А вот чтобы полноценно помочь, для этого нужно знать состав периферии как в части датчиков, так и в части управляемых устройств, знать что должна делать конструкция в целом, и как делать. А поскольку нам это неизвестно совсем, а Химику известно приблизительно, то конкретно ничего и не скажешь.

 

Например, управление с морды будет? В каком объеме? Будут кнопки? Сколько? Будут ли валкодеры? Будет ли ПДУ? Какого стандарта? В каком объеме? Что выводить на LCD? Какие режимы? Чем управлять в усилителе? Какие аппаратные решения управляемых узлов?

 

Тут блин всего-лишь одну семисегментную индикацию можно сделать десятком разных способов...

Ссылка на комментарий
Поделиться на другие сайты

  • Ответов 72
  • Создана
  • Последний ответ
Например, управление с морды будет? В каком объеме? Будут кнопки? Сколько? Будут ли валкодеры? Будет ли ПДУ? Какого стандарта? В каком объеме? Что выводить на LCD? Какие режимы? Чем управлять в усилителе? Какие аппаратные решения управляемых узлов?

Значит

так: внизу ложу схему и исходники (то что есть на данный момент). Схема пока не закончена, но я думаю алгоритм уже можно понять. Управление с пульта, энкодером и кнопками (АЦП). На шине i2c висят: часы реального времени DS1307, датчик температуры LM75, три звуковых процессора TDA7313, TDA8425, TDA9860 и синтезатор частоты TSA6060. Если разберусь с TDA7001 то будет она вместо 6060. Порт С управляет микроконтролером 90S2313 forum.datagor.ru/index.php?showtopic=2842. Так как исходников и какой либо документации на LA2785 нету, то я решил поставить на 2313 вместо кнопок ключи и управлять ими.

 

Теперь по исходнику. Отредактировал, добавил термометр, сделал опрос часов и датчика температуры по переполнению счетчика. И вот одна единственная ошибка в обработчике прерываний. Что может быть?

 

Помощь прошу только в исправлении ошибок, в алгоритме и написании хочу попробовать разобраться сам.

1.zip

Изменено пользователем химик
Ссылка на комментарий
Поделиться на другие сайты

...Помощь прошу только в исправлении ошибок, в алгоритме и написании хочу попробовать разобраться сам.

Первая ошибка орфографическая

interrapt[TIM1_OVF]...

нужно соответственно

interrupt[TIM1_OVF]...

После ее исправления вылезет еще одна ошибка из за

 while (1)

нужно так

 while (1) {}

 

И еще, я конечно не специалист в области программирования контроллеров, и это конечно не мое дело как делать, но как мне кажется ставить инициализацию устройств в прерывании нельзя.

Изменено пользователем hsl
Ссылка на комментарий
Поделиться на другие сайты

И еще, я конечно не специалист в области программирования контроллеров, и это конечно не мое дело как делать, но как мне кажется ставить инициализацию устройств в прерывании нельзя.

А если в обработчик прерываний внести

только вывод на дисплей, а инициализации до обработчика,

можно так?

 

 

Добавил в текст: декодер протокола RC-5, енкодер и клавиатуру АЦП.

Опять же ошибка синтаксиса.

Ссылка на комментарий
Поделиться на другие сайты

А если в обработчик прерываний внести

только вывод на дисплей, а инициализации до обработчика,

можно так?

 

 

Добавил в текст: декодер протокола RC-5, енкодер и клавиатуру АЦП.

Опять же ошибка синтаксиса.

Ну вообще инициализация устройств делается один раз в начале программы, как правило перед бесконечным циклом, вот как то так:

i2c_init();
rtc_init(0,0,0);
lm75_init(0,0,55,1);
lcd_init(16); // LCD module initialization
while (1) {}

 

Бегло просмотрел исходник... :smile:

Там более чем ошибка синтаксиса, вот так сразу все не поправить, надо будет просмотреть внимательнее, что бросилось в глаза

//////___ENCODER___/////////////////////////////////////////////////////////////////////////////////

unsigned char counter = 0; // переменная для счетчика

#define DIRECTION PIND0   // сюда подается логический уровень с вывода СН-В энкодера
void Scan_Encoder (void)
{		 
PORTB = counter		   // записуем значение для вывода в программу
   // External Interrupt 1 service routine
   interrupt [EXT_INT1] void ext_int1_isr(void)
   {  
		if (DIRECTION == 1)counter--;   // если на PIND0 логическая 1 - параметр уменьшаем (влево) 
		else counter++;				 // если лог. 0 - то параметр увеличиваем (вправо) 
   }
}  
//////___END__ENCODER___////////////////////////////////////////////////////////////////////////////

Объявлять переменны нужно либо в начале программы либо внутри функции, так вот как здесь объявление переменных посреди программы работать не будет, по крайней мере в CodeVisionAVR.

Еще момент, может меня и поправят более знающие люди, но помоему так грузить прерывания это перебор, туда нужно помещать только основное, что необходимо при работе.

Еще один момент в CodeVisionAVR, последовательность расположения функций имеет значение.

Нашел у себя один проект, недоделаный правда, в нем есть вывод на дисплей, обработка энкодера, обработка кнопки, передача данных по I2C, если надо могу скинуть для примера на мыло.

Изменено пользователем hsl
Ссылка на комментарий
Поделиться на другие сайты

Ну вообще инициализация устройств делается один раз в начале программы, как правило перед бесконечным циклом, вот как то так:

i2c_init();
rtc_init(0,0,0);
lm75_init(0,0,55,1);
lcd_init(16); // LCD module initialization
while (1) {}

 

Бегло просмотрел исходник... :smile:

Там более чем ошибка синтаксиса, вот так сразу все не поправить, надо будет просмотреть внимательнее, что бросилось в глаза

//////___ENCODER___/////////////////////////////////////////////////////////////////////////////////

unsigned char counter = 0; // переменная для счетчика

#define DIRECTION PIND0   // сюда подается логический уровень с вывода СН-В энкодера
void Scan_Encoder (void)
{		 
PORTB = counter		   // записуем значение для вывода в программу
   // External Interrupt 1 service routine
   interrupt [EXT_INT1] void ext_int1_isr(void)
   {  
		if (DIRECTION == 1)counter--;   // если на PIND0 логическая 1 - параметр уменьшаем (влево) 
		else counter++;				 // если лог. 0 - то параметр увеличиваем (вправо) 
   }
}  
//////___END__ENCODER___////////////////////////////////////////////////////////////////////////////

Объявлять переменны нужно либо в начале программы либо внутри функции, так вот как здесь объявление переменных посреди программы работать не будет, по крайней мере в CodeVisionAVR.

Еще момент, может меня и поправят более знающие люди, но помоему так грузить прерывания это перебор, туда нужно помещать только основное, что необходимо при работе.

Еще один момент в CodeVisionAVR, последовательность расположения функций имеет значение.

Нашел у себя один проект, недоделаный правда, в нем есть вывод на дисплей, обработка энкодера, обработка кнопки, передача данных по I2C, если надо могу скинуть для примера на мыло.

Конечно надо:smile:

Roman0v@rambler.ru

Изменено пользователем химик
Ссылка на комментарий
Поделиться на другие сайты

А какой будет энкодер? если такой как во вложении то с ним работать очень просто энкодер выдаёт 2-битный код грея вот такую последовательность: 00 10 11 01 00 10 11 01 00 10....... - при вращении в одном направлении, и соответственно, обратную, при вращении в противоположном.

Например, сейчас энкодер выдает код 10. Следующий код может быть либо 00, либо 11, в зависимости от направления вращения

так что в с некоторой частотой смотрите код который он выдает (частота опроса должна быть больше максимальной скорости "кручения" енкодера) небольшой анализ и все в ажуре.

DOC000048568.pdf

Изменено пользователем glazzz
Ссылка на комментарий
Поделиться на другие сайты

Не знаю... С кодом Грея не связывался. На механических контактах всегда будет дребезг. Длительность дребезга от 10 до 100 мс (от 1/100 до 1/10 c). Можно подавить его аппаратно, но зачем лишние детали?

Общий (обычно средний вывод) на землю, два остальных на входные пины сконфигурированные с подтягивающими резисторы.

Один выход енкодера тупо в прерывании (у меня 1200 раз в секунду) проверяю на состояние. Если после процедуры подавления дребезга определена смена состояния с 0 в 1, проверяю второй пин (для эстетов можно и на нем дребезг подавить, но обычно без этого можно обойтись). Если он в этот момент в 0, значит был "щелчок влево", если в единице - "щелчок вправо", выставляю соответствующий флаг (бит в переменной), а дальше уже делай с фактом поворота влево/вправо хочешь.

 

К сожалению, рабочий фрагмент кода привести не могу, сейчас я на работе, а паяю дома, но завтра выложу.

 

Да, если кто будет ваять что-нибудь с АЦП (например, кнопки), и контроллером будут AtMega 48/88/169/328, учтите, встроенное опорное напряжение у них не привычные нам 2,54 вольта, а 1,1 вольта. Я в это успешно впилился.

Изменено пользователем borman
Ссылка на комментарий
Поделиться на другие сайты

В общем так...

 

В начале программы в описаниях глобальных переменных:

 

// Для удобства пины ввода-вывода сопоставляем с символическими именами - куда что подключено по схеме

#define ENC1 PIND.0

#define ENC2 PIND.1

 

// Биты предыдущих состояний 1-го вывода енкодера - антидребезг

bit Enc11;

bit Enc12;

bit Enc13;

bit Enc14;

Bit Enc15;

// Биты предыдущих состояний 2-го вывода енкодера - антидребезг

bit Enc21;

bit Enc22;

bit Enc23;

bit Enc24;

Bit Enc25;

// Состояние выводов енкодера

bit Enc1;

Bit Enc2;

// "Обработанный сигнал" с энкодера определяется битами:

bit enc_right; // 1 - если был "щелчок вправо"

bit enc_left; // 1 - если был "щелчок вправо"

 

Далее в main{} после инициализации портов до цикла while(); :

 

// Заполняем значениями текущего состояния выводов

Enc11 = ENC1;

Enc12 = Enc11;

Enc13 = Enc11;

Enc14 = Enc11;

Enc15 = Enc11;

Enc21 = ENC2;

Enc22 = Enc21;

Enc23 = Enc21;

Enc24 = Enc21;

Enc25 = Enc21;

 

В обработчике прерывания таймера, у меня 1200 раз в секунду:

 

// Состояние выводов енкодера за последние 5 опросов

Enc25 = Enc24;

Enc24 = Enc23;

Enc23 = Enc22;

Enc22 = Enc21;

Enc21 = ENC2;

 

Enc15 = Enc14;

Enc14 = Enc13;

Enc13 = Enc12;

Enc12 = Enc11;

Enc11 = ENC1;

 

// Если предыдущее состояние вывода енкодера равно 0 и пять последних отсчетов равны 1, то состояние вывода энкодера становится равным 1 - антидребезг

if (((Enc21+Enc22+Enc23+Enc23+Enc25) == 5) && (ENC2 == 0)) {

ENC2 = 1;

};

 

// Если предыдущее состояние вывода енкодера равно 1 и пять последних отсчетов равны 0, то состояние вывода энкодера становится равным 0 - антидребезг

if (((Enc21+Enc22+Enc23+Enc23+Enc25) == 0) && (ENC2 == 1)) {

ENC2 = 0;

};

 

// Это было для второго вывода, определяющего направление. Факт щелчка энкодера определяем по нарастающему фронту на первом выводе аналогично:

// Если предыдущее состояние вывода енкодера равно 1 и пять последних отсчетов равны 0, то состояние вывода энкодера становится равным 0 - антидребезг

 

//Спадающий фронт:

if (((Enc11+Enc12+Enc13+Enc13+Enc15) == 0) && (ENC1 == 1)) {

ENC2 = 0;

};

 

// Нарастающий фронт

if (((Enc11+Enc12+Enc13+Enc13+Enc15) == 5) && (ENC1 == 0)) {

ENC2 = 1;

if (ENC2 == 0) {

enc_right = 1;

enc_left = 0;

};

if (ENC2 == 1) {

enc_right = 0;

enc_left = 1;

};

};

 

Собственно в том месте, где идет реакция на кручение енкодера (хоть в обработчике этого прерывания, хоть в в обработчике другого, хоть внутри цикла while), проверяем эти биты, выполняем действия - и не забываем их тут же сбросить!

 

Можно упростить, определив под хранение битов предыдущих отсчетов по одному байту, и вместо

 

Enc25 = Enc24;

Enc24 = Enc23;

Enc23 = Enc22;

Enc22 = Enc21;

 

выполнить сдвиг влево на 1, а текущий отсчет записать в младший бит операцией "побитное И" - "|".

 

Тогда в операторе if вместо длинного сложения и проверки суммы на равенство 0 или 5, просто проверять на равенство 0 или 255.

 

Но тогда частоту прерываний таймера (частоту опроса) поднято примерно до 2000 раз в секунду.

 

Размер кода уменьшится, быстродействие возрастет, но расплатимся памятью.

Ссылка на комментарий
Поделиться на другие сайты

Появилось несколько вопросов, в том числе и по железу.

1. Заказывал детали все для поверхностного монтажа. Вот теперь сижу и смотрю на ATMEGA16 TQFP44, а выдержат ли порта светодиоды приблизительно по 30мА и всего их 9шт. Когда заказывал, то думал что этот корпус чуть по больше. Паять не боюсь.

2. Байт АСК, он для всех микросхем управляемых по I2C равен 0b00010000?

3. Что за трех проводный интерфейс в LM7001 с выводами CE, CL, DATA?

Ссылка на комментарий
Поделиться на другие сайты

Появилось несколько вопросов, в том числе и по железу.

1. Заказывал детали все для поверхностного монтажа. Вот теперь сижу и смотрю на ATMEGA16 TQFP44, а выдержат ли порта светодиоды приблизительно по 30мА и всего их 9шт. Когда заказывал, то думал что этот корпус чуть по больше. Паять не боюсь.

 

Смотрим даташит на Atmega16A, не маленькую выжимку из 19 страниц, а большой из 352 страниц, раздел 27. Electrical Characteristics.

 

DC Current per I/O Pin ............................................... 40.0 mA

DC Current VCC and GND Pins................. 200.0mA PDIP and 400.0mA TQFP/MLF

 

То есть через пин можно пропускать до 40 мА, а через линии питания или земли в твоем случае до 400 мА. Далее:

 

Although each I/O port can source more than the test conditions (20 mA at Vcc = 5V, 10 mA at Vcc = 3V) under steady state

conditions (non-transient), the following must be observed:

PDIP Package:

1] The sum of all IOH, for all ports, should not exceed 200 mA.

2] The sum of all IOH, for port A0 - A7, should not exceed 100 mA.

3] The sum of all IOH, for ports B0 - B7,C0 - C7, D0 - D7 and XTAL2, should not exceed 100 mA.

TQFP and QFN/MLF Package:

1] The sum of all IOH, for all ports, should not exceed 400 mA.

2] The sum of all IOH, for ports A0 - A7, should not exceed 100 mA.

3] The sum of all IOH, for ports B0 - B4, should not exceed 100 mA.

4] The sum of all IOH, for ports B3 - B7, XTAL2, D0 - D2, should not exceed 100 mA.

5] The sum of all IOH, for ports D3 - D7, should not exceed 100 mA.

6] The sum of all IOH, for ports C0 - C7, should not exceed 100 mA.If IOH exceeds the test condition, VOH may exceed the

related specification. Pins are not guaranteed to source current greater than the listed test condition.

 

Собственно, указано, сумма токов каких пинов НЕ должна превышать 100 мА.

9х30 = 270, если раскидать их разным портам, должно выдержать. Однако я бы не рисковал.

 

Вообще я удивлен 30 мА на светодиод. Обычно они 20 мА по номиналу. Можно взять диод поярче и питать током поменьше, 10 мА ПМСМ достаточно.

 

Если есть опасения за перегрузка портов МК, 9 резисторов по 1 кОм и 9 штук КТ315 или КТ3102 в ключевом режиме.

 

Но лучше КР514КТ1 (6 рублей за корпус в рознице) - в корпусе 9 штук инвертирующих ключей с открытым коллектором, даташит могу скинуть, до 400 мА на один пин. Корпус ДИП24 широкий, распиновка удобная для разводки - все входы с одной стороны, все выходы - с другой.

 

Выход с МК вешаешь на вход КТ1, светодиод анодом к +5В питания, катод к выходу КТ1. Будет гореть при 0 на выходе, а поскольку это инвертор, но вход с МК нужно подать 1.

 

2. Байт АСК, он для всех микросхем управляемых по I2C равен 0b00010000?

 

Вот с I2C не работал. Пока еще. Не разбирался с протоколом, но чутье подсказывает, что ACK - это "ответ", то есть сигнал ведомому чипу, что ведущий дальше будет ждать данных от ведомого, и разрешает передачу данных "вверх". Хотя скорее всего ошибаюсь.

 

3. Что за трех проводный интерфейс в LM7001 с выводами CE, CL, DATA?

 

ЕМНИП, CE - это Chip Select, Chip Enable, то есть чтобы вести обмен с конкретным чипом, ему нужно выставить разрешающий уровень на этом входе, остальным чипам - запрещающий.

CL - Clock, тактовые ипульсы, DATA - она data и есть, последовательные данные, тактируемые со входа CL.

 

Сейчас даташит скачаю и поcмотрю... Это LM7001 - это синтезатор частоты? Есть два вида - LM7001 - там надо вручную дергать сигналы на его входе, и LM7001 с управлением по протоколу I2C. Собственно физически по сигналам там все одинаково, однако в LM7001M поверх сигналов положен протокол обмена I2C.

 

При ручном обмене там сдвиговой 24-битовый регистр на входе и регистр-защелка для хранения принятого. Собственно все режимы работы потрохов чипа берутся из защелки - в процессе принятия данных в сдвиговом регистре там данные пляшут как пьяные девки, и пока обмен не закончится, чип будет раком стоять, потому и нужна защелка.

 

Там диаграмма обмена приведена. Нормально CE в 0, чип не реагирует на внешние раздражители и работате по данным, находящимся в защелке. Прием данных по переднему фронту тактового сигнала.

 

Сначала Устанавливаем CL в 0. И ТОЛЬКО ПОТОМ поднимаем CE в 1 - чип готов принимать данные.

Устанавливаем бит данных на входе DATA в нужный уровень, CL в 1 - данные вошли в чип, затем CL возвращаем в 0. И так 24 раза - по числу бит.

После чего опускаем CE в 0, и на спаде сигнала происходит запись данных из регистра сдвига в регистр защелку, и ТОЛЬКО после этого после чего режим работы чипа определен данными, переданными в него.

Изменено пользователем borman
Ссылка на комментарий
Поделиться на другие сайты

Для публикации сообщений создайте учётную запись или авторизуйтесь

Вы должны быть пользователем, чтобы оставить комментарий

Создать учетную запись

Зарегистрируйте новую учётную запись в нашем сообществе. Это очень просто!

Регистрация нового пользователя

Войти

Уже есть аккаунт? Войти в систему.

Войти
  • Последние посетители   0 пользователей онлайн

    • Ни одного зарегистрированного пользователя не просматривает данную страницу

×
×
  • Создать...