|
Простенькая программка измерения длительности импульса. |
|
|
|
Aug 30 2008, 08:30
|

Местный
  
Группа: Участник
Сообщений: 355
Регистрация: 27-03-07
Из: Україна, Чуднів
Пользователь №: 26 530

|
Цитата(rv3dll(lex) @ Aug 30 2008, 11:00)  если импульс гладкий ез промсечек надо после прерывания поменять в регистре статуса прерывания полярность Ну, если и есть то можна сгладить простейшим интегратором - RC -фильтром подобрав тау под мин длит импульса.
--------------------
нельзя недооценивать предсказуемость глупости
|
|
|
|
|
Aug 30 2008, 19:53
|

Местный
  
Группа: Участник
Сообщений: 355
Регистрация: 27-03-07
Из: Україна, Чуднів
Пользователь №: 26 530

|
Цитата(Зверюга @ Aug 30 2008, 18:29)  Я вот например запустил CodeVision Wisard и мне совершенно непонятно, как привязать внешнее прерывание к запуску и остановке таймера. я тоже извиняюсь, только после именин крёсника. Во первых про остановку таймера я ничего не говорил. во вторых, режим захвата общеизвестен. чего уж тут обяснять. зверюга, а при чём здесь помощник CodeVision ? ну а как померять период? зверюга , представьте себе ситуацию, когда Ваш счётчик сам себе считает. Ну и пускай себе считает, ведь правда? мы инициализируем периферию так, что бы обрабатывать прерывание по фронту или по спаду, как Вам уже удобно будет, на любителя. счётчик себе считает, ну и пускай..... но тут приходит спад (Falling Edge) измеряемого сигнала и у нас возникает прерывание поскольку мы настроили прерывание по Falling Edge (ну так нам захотелось). представим себе что счётчик считал себе и никто его не трогал. тут возникло наше прерывание. ну и тут остановки или запуска нету. в общем, когда происходит захват то состояние счётчика копируется в регистр захвата. если это понятно, тогда обясню следующее разница в счёте регистра захвата между первым прерыванием и вторым будет равна периоду Вашего измеряемого сигнала умноженную на частоту тактирования вашего счетчика и делённую на величину предделителя. я даже в таком состоянии немогу понять какой код Вы хотите увидеть?тут то писать нечего
--------------------
нельзя недооценивать предсказуемость глупости
|
|
|
|
|
Aug 31 2008, 13:25
|
Местный
  
Группа: Свой
Сообщений: 413
Регистрация: 15-12-06
Пользователь №: 23 563

|
Боюсь Ваш метод мне не подойдет. Объясню: время необходимо измерять довольно точно. Ввиду этого я буду использовать 16-ти битный таймер, источником для счета выберу System clock. Таким образом получу переполнение таймера за 4095,9375 мкс. А если длительность импульса будет больше указанной величины? Я планирую сделать так: По переполнению таймера генерировать прерывание, в обработчике которого некая величина cycles будет инкрементироваться. А контроллировать измеряемый импульс я буду внешним прерыванием. По спаду имульса на входе INT0 будет генерироваться прерывание, в обработчике которого будет производиться операция (cycles*65535+состояние счетчика на данны момент) / 16 - получаем длительность импульса в микросекундах при частоте кварца 16 МГц. После чего счетчик сбрасывается, переменная cycles обнуляется. Уточню - мне нужно не время импульса, а время от фронта до следущего фронта. То есть период. Кроме того, использоваться бедт не только INT0, но и INT1, INT2, импульсы на которые будут приходить поочередно, а обработчк будет один и тот же. Если предложенный мной алгоритм с использованием не только счетчика но и внешнего прерывания слишком сложен и объясняется незнанием мной всех возможностей счетчика, укажите мне на это. В таймерах/счетчиках я полный ноль, заглянул в руководство - там 50 страниц с дикими 5-6-ти буквенными похожими друг на друга труднозапоминаемыми аббревиатурами. Господа, я знаю, что разбираться с этим буду недели две, а что конечный результат инициализации строк таймера займет 5-6 строк. Будьте добры, помогите с примером кода, а я изменяя его и экспериментирую, как-нибудь дальше разберусь. Вот мой код: Код interrupt [TIM1_OVF] void timer1_ovf_isr(void) { lcd_setxy(2,15); lcd_str_fl("timer is overflow",f8x14,green);//ñòðîêà èç flash
cycle++; }
void main(void) { TCCR1A=0x00; TCCR1B=0x01; TCNT1H=0x00; TCNT1L=0x00; ICR1H=0x00; ICR1L=0x00; OCR1AH=0x00; OCR1AL=0x00; OCR1BH=0x00; OCR1BL=0x00; ........ .........
for (;;) { lcd_setxy(32,50); lcd_str_ram(cycle, f8x8,textcolor);//ñòðîêà èç ram }
} Если таймер хотя бы один раз переполнится, на экран должна вылезти надпись "timer is oferflow". А если он переполняется неоднократно, то постоянно будет обновляться значение переменной cycle. На экране же "0". Таймер не запущен? Генерировал код при помощи CodeVision Wizard.
|
|
|
|
|
Aug 31 2008, 13:57
|

Местный
  
Группа: Участник
Сообщений: 355
Регистрация: 27-03-07
Из: Україна, Чуднів
Пользователь №: 26 530

|
Вы глобально не разрешили прерывания. инициализация таймера правильная, как Вы и хотели. для КВ, непомню но вроде вот так напишите в мейне перед циклом Код #asm sei #endasm Цитата(Зверюга @ Aug 31 2008, 16:25)  время необходимо измерять довольно точно. Ввиду этого я буду использовать 16-ти битный таймер, источником для счета выберу System clock. Таким образом получу переполнение таймера за 4095,9375 мкс. Если таймер хотя бы один раз переполнится, на экран должна вылезти надпись "timer is oferflow". А если он переполняется неоднократно, то постоянно будет обновляться значение переменной cycle. ЖКИ графический, успеет? четыре милисекунды слишком мало. Цитата(Зверюга @ Aug 31 2008, 16:25)  время необходимо измерять довольно точно. Ввиду этого я буду использовать 16-ти битный таймер, источником для счета выберу System clock. Таким образом получу переполнение таймера за 4095,9375 мкс. А если длительность импульса будет больше указанной величины? А чё Вам мешает подсчитывать колличество переполнений, а в регистре захвата будете иметь значение счётчика на момент прихода следующего фронта? о, всё придумано уже до меня ссылка.
--------------------
нельзя недооценивать предсказуемость глупости
|
|
|
|
|
Aug 31 2008, 14:13
|
Местный
  
Группа: Свой
Сообщений: 413
Регистрация: 15-12-06
Пользователь №: 23 563

|
Цитата ЖКИ графический, успеет? четыре милисекунды слишком мало. Вы правы. Разрешил глобально прерывания, ЖКИ перестал выводить на экран))) Убрал все из обработчика прерываний, даже остановил таймер (TCCR1B=0x00;) - тоже не работает. Сам факт разрешеиня прерываий не дает работать ЖКИ. Поставил #asm cli #endasm до начала обращения к ЖКИ и #asm sei #endasm после. Выясняется, что sei вызывает перезагрузку ЖКИ... Что делать.. Цитата о, всё придумано уже до меня ссылка. Прочитано до Вас. Там по-видимому для WinAVR. По крайнй мере TIMSK |= (1 << TOIE1); переваривать не хочет, TOIE1 не знает. Так все-таки - куда точно ставить разрешение прерываний? Поставил перед void main() - ЖКИ не перегружается но и проргамма не работает...
|
|
|
|
|
Aug 31 2008, 14:31
|

Местный
  
Группа: Участник
Сообщений: 355
Регистрация: 27-03-07
Из: Україна, Чуднів
Пользователь №: 26 530

|
Цитата(Зверюга @ Aug 31 2008, 17:13)  Прочитано до Вас. Там по-видимому для WinAVR. По крайнй мере TIMSK |= (1 << TOIE1); переваривать не хочет, TOIE1 не знает.
Так все-таки - куда точно ставить разрешение прерываний? Поставил перед void main() - ЖКИ не перегружается но и проргамма не работает... у вашего компилятора нету битовых определений регистров. в регистре TIMSK, бит TOIE1 третий для Вашего МК. Поможет определение Код #define TOIE1 2 тогда будет работать выражение приведённое вами выше. Цитата(Зверюга @ Aug 31 2008, 17:13)  Так все-таки - куда точно ставить разрешение прерываний? Поставил перед void main() - ЖКИ не перегружается но и проргамма не работает... Глобальное разрешение прерываний пишут в мейне непосредственно перед бессконечным циклом for (;;). На моменте отладки в прерывании переполнения таймера запретите прерывания, выведите надпись, и разрешите перед выходом.
--------------------
нельзя недооценивать предсказуемость глупости
|
|
|
|
|
Aug 31 2008, 14:53
|
Местный
  
Группа: Свой
Сообщений: 413
Регистрация: 15-12-06
Пользователь №: 23 563

|
Спасибо конечно, но вот разрешение прерываний не дает работать ЖКИ.. Для чистоты эксперимента убрал все лишнее, убрал инициализацию таймера, убрал обработчик прерывания - просто сделал sei - перезагружается.. УХ ТЫ!!!! Посмотрите код! Запретил прерывания, инициализировал экранчик. Поставил задержку в 3 секунды - чтобы хоть посмотреть на черный экран. Затем включил прерывания. - Экран стал моргать с периодичнстью в 3 секунды. ЭТО НЕ ЖКИ, ЭТО КОНТРОЛЛЕР РЕСЕТИТСЯ. Почему? Куда копать? Вот код: Код #include <mega32.h> #include <delay.h> #include <disp.h> #include <stdio.h> #include <defines.c> //**************************************************** #define INT_ON #asm("sei") #define INT_OFF #asm("cli")
u08 variable; ui16 textcolor; // color of text ui16 backcolor; // color of background
ui16 varvar; volatile int cycle=0; ///////////////////////////////////////////////////
interrupt [TIM1_OVF] void timer1_ovf_isr(void) { //lcd_setxy(2,15); // lcd_str_fl("timer_ovfl",f8x14,green);//ñòðîêà èç flash
cycle++; }
void main(void) {
INT_ON; /* TCCR1A=0x00; TCCR1B=0x03; TCNT1H=0x00; TCNT1L=0x00; ICR1H=0x00; ICR1L=0x00; OCR1AH=0x00; OCR1AL=0x00; OCR1BH=0x00; OCR1BL=0x00;
*/
//================================================= varvar = 4500 + 60123;
INT_OFF; lcd_init(); backcolor=black; textcolor=yellow;
lcd_clr(); fill_screen(black); delay_ms(3000); INT_ON;
} Для общей информации - вот библиотека ЖКИ При этом регистр MCUCSR=0x03, то есть оба бита равны 1
|
|
|
|
|
Aug 31 2008, 15:18
|

Местный
  
Группа: Участник
Сообщений: 355
Регистрация: 27-03-07
Из: Україна, Чуднів
Пользователь №: 26 530

|
Цитата(Зверюга @ Aug 31 2008, 17:53)  ЭТО НЕ ЖКИ, ЭТО КОНТРОЛЛЕР РЕСЕТИТСЯ. Почему? Куда копать? При этом регистр MCUCSR=0x03, то есть оба бита равны 1 Как у Вас организован внешний сброс? Чё к ресету подсоединено и как? Цитата Bit 1 – EXTRF: External Reset Flag This bit is set if an External Reset occurs. The bit is reset by a Power-on Reset, or by writing a logic zero to the flag. • Bit 0 – PORF: Power-on Reset Flag This bit is set if a Power-on Reset occurs. The bit is reset only by writing a logic zero to the flag. To make use of the Reset Flags to identify a reset condition, the user should read and then reset the MCUCSR as early as possible in the program. If the register is cleared before another reset occurs, the source of the reset can be found by examining the Reset Flags. Вотчдог не включён? Ещё, запитываете каким образом, стабилизатор и БП не слабенькие? оф: чем отлаживаете?
--------------------
нельзя недооценивать предсказуемость глупости
|
|
|
|
|
Aug 31 2008, 15:20
|
Местный
  
Группа: Свой
Сообщений: 413
Регистрация: 15-12-06
Пользователь №: 23 563

|
Цитата Как у Вас организован внешний сброс?
Чё к ресету подсоединено и как? К ресету кнопка, без резистора - никогда до этого ресеты не случались. В этом может быть причина? Включение пррываний генерирует помехи или просадки? Просто ща занят, подпаять нет времени... Песик выключен.
|
|
|
|
|
Aug 31 2008, 15:33
|

Местный
  
Группа: Участник
Сообщений: 355
Регистрация: 27-03-07
Из: Україна, Чуднів
Пользователь №: 26 530

|
Цитата(Зверюга @ Aug 31 2008, 18:20)  К ресету кнопка, без резистора - никогда до этого ресеты не случались. В этом может быть причина? Включение пррываний генерирует помехи или просадки? Просто ща занят, подпаять нет времени... да именно, об этом Вам и говорят установленные флаги. Попробуйте сначала исключить ресет а потом уже подумаем нащёт просадок. может ещё детектор питания (БОД) не так настроен. как появится время, резистор 1К к питанию и к ресет, конденсатор 10нан к ресету и к корпусу.
--------------------
нельзя недооценивать предсказуемость глупости
|
|
|
|
|
Aug 31 2008, 17:46
|
Местный
  
Группа: Свой
Сообщений: 413
Регистрация: 15-12-06
Пользователь №: 23 563

|
Подпаял резистор, конденсатор ненашел. Все равно ресетится, но уже со значением MCUCSR=0x01, то есть бит, означающий что на ресет подан низкий уровень равен нулю. Вопрос: значит, ресет от помех все-таки был, сейчас помеха (0 на ресете) не вылазит - мне искать конденсатор? Проблема то вроде устранена. ПРо ватчдог я соврал - сейчас проверяю включен он или выключен. Так, если я правильно понял: Цитата Для того, чтобы включить сторожевой таймер, достаточно установить в 1 бит WDE -Watch Dog Enable. А вот выключить так просто не получится - и сделано это для защиты от тех же сбоев... Для выключения надо проделать следующие действия: Записать одновременно в WDE и WDTOE значения "1" В течение 4-х тактов процессора записать "0" в WDE. ТО выключить сторожевой таймер если он включен нужно так: WDTCR=0x18; WDTCR=0x10; Делаю это. Происходит ресет со значением WDTCR=0, MCUCSR=1; То же и без принудительного выключения. Кстати, почему вы решили что он включен - по умолчанию он ведь выключен. Что за бред.... BOD - если вы имеете ввиду фьюзы, то у меня BODEN=1. Далее..... Последовал совету: Цитата Следовательно, если в программе нужно определять режим сброса - то после анализа этих бит их просто нужно установить в "0". Тогда сброс по сторожевому таймеру можно будет определить по отсутствию "1" в вышеописанных битах. Сделал так: Код void main(void) {
//WDTCR=0x18; //WDTCR=0x10;
lcd_init(); backcolor=black; textcolor=yellow;
lcd_clr(); fill_screen(black);
lcd_setxy(20,20); lcd_str_fl("MCUCSR=",f8x14, textcolor); lcd_str_ram(MCUCSR,f8x14, textcolor); lcd_setxy(20,40); lcd_str_fl("WDTCR=",f8x14, textcolor); lcd_str_ram(WDTCR,f8x14, textcolor);
MCUCSR=0x00; delay_ms(3000); INT_ON; это включение прерывания, установлено черех #define
} В итоге на экран выводится WDTCR=0, MCUCSR=0; Получается что сброс по сторожевому таймеру? Убираю комментарии со строк WDTCR=0x18; WDTCR=0x10; (опять таки, если я правильно понял как отключить сторожа) - тот же эффект.
|
|
|
|
|
Aug 31 2008, 18:53
|

Местный
  
Группа: Участник
Сообщений: 355
Регистрация: 27-03-07
Из: Україна, Чуднів
Пользователь №: 26 530

|
Цитата(Зверюга @ Aug 31 2008, 20:46)  Получается что сброс по сторожевому таймеру? Убираю комментарии со строк WDTCR=0x18; WDTCR=0x10; (опять таки, если я правильно понял как отключить сторожа) - тот же эффект. детектор питания отключён, с ресетом Вы справились, правда это не защитит от наносекундных помех без хорошей земли (разводки) и конденсатора. Получается что сторожевой таймер у вас командовал парадом. Ну и начинайте уже заниматься основной задачей. Вот как я планирую сделать тахометр: Код //Chip type: ATmega8535 //Chip clock 14,745600Mh /******************************************************************************* * Тахометр четырёхтактного двигателя. Импульсы подаются с прерывателя. За один * оборот проходит два импульса. Для измерения частоты оборотов двигателя * исспользуется таймер один. Он запущен в свободном режиме счёта. Предделитель * тактовой выбран 64, т.о. тактовая таймера составляет 230,400 kHz. Для даного * таймера разрешено два прерывания: по завату по спаду импульса и по переполнению. * Для измерения периода следования входных импульсов с прерывателя исспользовано * прерывание режима захвата. Т.о. производится измерение полупериода (два импульса * за оборот). * В прерывании захвата производится копирование состояние счётчика на момент прерывания * из регистра захвата ICR1. Прерывание переполнение происходит каждые 0.25мс в котором * происзводится обновление информации выводимой на ЖКИ. ******************************************************************************* #include <inavr.h> #include <ioavr.h> #include <stdint.h> #include <stdlib.h> #define OborotiZaMinConst 6912000 /* Определение глобальных переменных*/ signed int CaptureTmp, CaptureOld; signed int PPeriod; div_t dtmp; char str_tmp[6];
// Timer 1 overflow interrupt service routine #pragma vector = TIMER1_OVF_vect __interrupt void Timer1_overflow(void) { //частное (quot) и остаток (rem) /*div_t typedef struct { int quot, rem; } div_t; */ char i; signed int OborotiZaMin; str_tmp[5] = 0; OborotiZaMin = (OborotiZaMinConst + (PPeriod >> 1)) / PPeriod;
dtmp = div(OborotiZaMin, 10); str_tmp[4] = dtmp.rem + '0'; dtmp = div(dtmp.quot, 10); str_tmp[3] = dtmp.rem + '0'; dtmp = div(dtmp.quot, 10); str_tmp[2] = dtmp.rem + '0'; dtmp = div(dtmp.quot, 10); str_tmp[1] = dtmp.rem + '0'; str_tmp[0] = dtmp.quot + '0'; // Гашение незначащих нулей for (i = 0; i < 4; ++i) if (str_tmp[i] == '0') str_tmp[i] = ' '; else break;
} // Timer 1 input capture interrupt service routine #pragma vector = TIMER1_CAPT_vect __interrupt void Timer1_input_capture(void) { CaptureTmp = ICR1; PPeriod = CaptureTmp - CaptureOld; CaptureOld = CaptureTmp; } void TimOneInit (void){ // Timer/Counter 1 initialization // Clock source: System Clock // Clock value: 230,400 kHz // Mode: Normal top=FFFFh // OC1A output: Discon. // OC1B output: Discon. // Noise Canceler: Off // Input Capture on Falling Edge // Timer 1 Overflow Interrupt: On // Input Capture Interrupt: On // Compare A Match Interrupt: Off // Compare B Match Interrupt: Off TCCR1A=0x00; TCCR1B=0x03; TCNT1H=0x00; TCNT1L=0x00; ICR1H=0x00; ICR1L=0x00; OCR1AH=0x00; OCR1AL=0x00; OCR1BH=0x00; OCR1BL=0x00; } int main( void ) { TimOneInit(); _enableinterupt(); for(;;){ }
} В общем, код ещё на стадии разработки, но Вам для маленького направления пойдёт.
--------------------
нельзя недооценивать предсказуемость глупости
|
|
|
|
|
Aug 31 2008, 19:23
|

Местный
  
Группа: Участник
Сообщений: 355
Регистрация: 27-03-07
Из: Україна, Чуднів
Пользователь №: 26 530

|
Цитата(Зверюга @ Aug 31 2008, 22:06)  Я всего лишь добился что в MCUCSR второй бит стал равен нулю, то есть не было зафиксировано низкого уровня на ресете. Это уже хорошо. был - бы конденсатор было бы нелогично не зафиксировать низкий уровень. Поскольку вы могли и раньше включить его, или МК поддался воздействию помехи он мог сам включиться хотя это уже из ряда фантастики. теперь из ДШ выключение дога Код void WDT_off(void) { /* reset WDT */ _WDR(); /* Write logical one to WDTOE and WDE */ WDTCR |= (1<<WDTOE) | (1<<WDE); /* Turn off WDT */ WDTCR = 0x00; }
--------------------
нельзя недооценивать предсказуемость глупости
|
|
|
|
|
Aug 31 2008, 19:39
|
Местный
  
Группа: Свой
Сообщений: 413
Регистрация: 15-12-06
Пользователь №: 23 563

|
ТАК, ПОХОЖЕ ГЛЮК ВСЕ ТАКИ СВЯЗАН С БИБЛИОТЕКОЙ ЖКИВывел содержимое регистров на диоды портов моей отладочной платы, расставил по ходу программы маячки, выяснилось - если инициализировать дисплей, очишать его экран, то все ОК, ресета нет. Если же пытаться вывести что-то на экран, и после этого включить прерывания - происходит РЕСЕТ. ОДНАКО, если после выведения на экран вызвать функцию библиотеки lcd_clr(), и после этого включить прерывание - РЕСЕТ не происходит. Если включать прерывания в самом начале основного цикла - то РЕСЕТ происходит при инициализации дисплея. Господа, мне остается только привести здесь текст библиотеки и попросить вас взглянуть, чего вне есть потенциально опасного в плане ресета, может конфликты какие? Код #include <spi.h> #include <delay.h> #include <stdio.h> #include <mega32.h> #include <fonts.c> #include <defines.c>
u08 buffer[1][5]; u08 posx,posy;
#define LCD_PORT PORTB // экран сидит на порте B #define LCD_DDR DDRB //
#define LCD_CS 2 // биты порта #define LCD_RESET 3 #define LCD_RS 4 #define LCD_MOSI 5 #define LCD_MISO 6 #define LCD_SCK 7
#define SPIF 7 #define SPI2X 0
#define SPR0 0 #define SPR1 1 #define SPHA 2 #define SPOL 3 #define MSTR 4 #define DORD 5 #define SPE 6 #define SPIE 7
#define DISP_W 132 #define DISP_H 176 #define CHAR_H 14 #define CHAR_W 8 #define TEXT_COL 16 #define TEXT_ROW 12
// INIT1:; 24bytes const ui16 INIT1[12]={0xFDFD,0xFDFD,0xEF00,0xEE04,0x1B04,0xFEFE,0xFEFE,0xEF90,0x4A04,0x7F3F,0xEE 04,0x4306};
//INIT2:; 40bytes const ui16 INIT2[20]={0xEF90,0x0983,0x0800,0x0BAF,0x0A00,0x0500,0x0600,0x0700,0xEF00,0xEE0C,0xEF 90,0x0080,0xEFB0,0x4902, 0xEF00,0x7F01,0xE181,0xE202,0xE276,0xE183};
//INIT3:; 2bytes const ui16 INIT3[1]={0x8001}; /* // INIT1:; 24bytes const u08 INIT1[24]={0xFD,0xFD,0xFD,0xFD,0xEF,0x00,0xEE,0x04,0x1B,0x04,0xFE,0xFE,0xFE,0xFE,0xEF ,0x90,0x4A,0x04,0x7F,0x3F,0xEE,0x04,0x43,0x06};
//INIT2:; 40bytes const u08 INIT2[40]={0xEF,0x90,0x09,0x83,0x08,0x00,0x0B,0xAF,0x0A,0x00,0x05,0x00,0x06,0x00,0x07 ,0x00,0xEF,0x00,0xEE,0x0C,0xEF,0x90,0x00,0x80,0xEF,0xB0,0x49,0x02, 0xEF,0x00,0x7F,0x01,0xE1,0x81,0xE2,0x02,0xE2,0x76,0xE1,0x83};
//INIT3:; 2bytes const u08 INIT3[2]={0x80,0x01}; */
//===========================================port_init============================ ==============================
void port_init(void) { // setup serial data I/O pins
LCD_PORT.LCD_RESET=0; // reset display LCD_DDR.LCD_RESET=1; // set reset as output
LCD_DDR.LCD_MOSI=1; // MOSI must be set as output for SPI LCD_PORT.LCD_MOSI=1; // MOSI must be set as output for SPI LCD_PORT.LCD_CS=0; // deselect display LCD_DDR.LCD_CS=1; // SS must be output for Master mode to work
LCD_PORT.LCD_SCK =0; // set SCK low LCD_DDR.LCD_SCK=1; // set SCK as output LCD_PORT.LCD_MISO=1; // enable pull up of MISO to avoid floating input
LCD_PORT.LCD_RS=1; // RS=high LCD_DDR.LCD_RS=1; // RS is output SPCR = (1<<SPE)|(1<<MSTR)|(0<<SPR1)|(0<<SPR0); SPSR = (1<<SPI2X); delay_ms(4); // wait one ms to have a nice reset LCD_PORT.LCD_RESET=1; // release reset }
//******************************************************************************** ******************
void lcd_wrcmd16(ui16 dat) { lcd_wrcmd((dat>>8)); lcd_wrcmd(dat); } //******************************************************************************** ****************** void lcd_wrdat16(ui16 dat) { lcd_wrdata(dat>>8); lcd_wrdata(dat); } //******************************************************************************** ******************
void fill_screen(ui16 color) { ui16 i=0; lcd_wrcmd16(0xEF90); lcd_wrcmd16(0x0500); lcd_wrcmd16(0x0600); lcd_wrcmd16(0x0700); for (i=0; i<DISP_W*DISP_H; i++)lcd_wrdat16(color); } //******************************************************************************** ******************
void lcd_wrcmd(u08 dat) { LCD_PORT.LCD_CS=0; LCD_PORT.LCD_RS=1; spi_send(dat); } //******************************************************************************** ******************
void lcd_wrdata(u08 dat) {
LCD_PORT.LCD_CS=0; LCD_PORT.LCD_RS=0; spi_send(dat); }
//******************************************************************************** ******************
void spi_send(u08 dat) {
#asm
ld r26,y sbi 0xd,7 out 0xf,r26 SPI_SEND_2: sbis 0xe,7 rjmp SPI_SEND_2 sbi 0x18,2 #endasm
}
//******************************************************************************** ******************
void spi_send0(u08 dat) { spi_send(dat); spi_send(0x00); }
//******************************************************************************** ******************
void lcd_cspulse(void) { LCD_PORT.LCD_CS = 1; #asm("nop"); LCD_PORT.LCD_CS = 0; }
//******************************************************************************** ******************
void lcd_init(void) { ui16 i=0;
LCD_PORT.LCD_CS=1; LCD_DDR.LCD_CS=1; port_init();
LCD_PORT.LCD_CS=0; delay_ms(4); LCD_PORT.LCD_RS=1; for (i=0;i<12;i++) lcd_wrcmd16(INIT1[i]); delay_ms(7); for (i=0;i<20;i++) lcd_wrcmd16(INIT2[i]); delay_ms(50);
for (i=0;i<1;i++) lcd_wrcmd16(INIT3[i]); delay_ms(5);
lcd_clr(); LCD_PORT.LCD_CS=1; }
//******************************************CHAR********************************** *****************
void put_char(char c,u08 font,ui16 color) { u08 h,ch,p,mask,font_height,font_width; char i, j; ui16 b; u08 rot=0; if(font==f8x14) { font_height=14; font_width=8; lcd_wrcmd16(0xEF90); lcd_wrcmd16(0x0504); lcd_wrcmd16(0x0800+posy); lcd_wrcmd16(0x0A00+posx); lcd_wrcmd16(0x0900+posy+font_height-1); lcd_wrcmd16(0x0B00+posx+font_width-1); for (h=0; h<font_height; h++) // every column of the character { ch=font8x14[ c-32 ][font_height-h-1]; // mask=0x80; for (p=0; p<font_width; p++) // write the pixels { if (ch&mask) { lcd_wrdat16(textcolor); } else { lcd_wrdat16(backcolor); } mask=mask/2; } } } if(font==f8x8) { font_height=8; font_width=8; lcd_wrcmd16(0xEF90); lcd_wrcmd16(0x0500); lcd_wrcmd16(0x0800+posy); lcd_wrcmd16(0x0A00+posx); lcd_wrcmd16(0x0900+posy+font_height-1); lcd_wrcmd16(0x0B00+posx+font_width-1); for (h=0; h<font_height; h++) // every column of the character { ch=font8x8[ c-32 ][h]; mask=0x80; for (p=0; p<font_width; p++) // write the pixels { if (ch&mask) { lcd_wrdat16(textcolor); } else { lcd_wrdat16(backcolor); } mask=mask/2; } } } posx = posx + font_width; }
//******************************************************************************** ******************
void lcd_setxy(u08 x, u08 y) { posx=x; posy=y;
//lcd_wrcmd16(0x0504); //lcd_wrcmd16(0x0800+x); //lcd_wrcmd16(0x0A00+y); //lcd_wrcmd16(0x0900+x+8-1); //lcd_wrcmd16(0x0B00+y+14-1); } //******************************************************************************** ******************
void lcd_clr(void) { #asm push r30 push r31
ldi r24,0xEF rcall lcd_wrcmd ldi r24,0x90 rcall lcd_wrcmd ldi r24,0x05 rcall lcd_wrcmd ldi r24,0x00 rcall lcd_wrcmd ldi r24,0x08 rcall lcd_wrcmd ldi r24,0x00 rcall lcd_wrcmd ldi r24,0x0A rcall lcd_wrcmd ldi r24,0x00 rcall lcd_wrcmd ldi r24,0x09 rcall lcd_wrcmd ldi r24,0x84 rcall lcd_wrcmd ldi r24,0x0B rcall lcd_wrcmd ldi r24,0xB0 rcall lcd_wrcmd
ldi r31, 0xB6 ldi r30, 0xB1 ldi r24, 0xFF LCD_CLEAR_1: rcall lcd_wrdata sbiw r30,1 brne LCD_CLEAR_1 pop r31 pop r30 ret lcd_wrcmd: cbi 0x18,2 sbi 0x18,4 rjmp SPI_SEND lcd_wrdata: cbi 0x18,2 cbi 0x18,4 SPI_SEND: sbi 0xd,7 out 0xf,r24 SPI_SEND_0: sbis 0xe,7 rjmp SPI_SEND_0 in r0,0xf sbi 0x18,2 ret #endasm }
//**********************************рисуем пиксели в коорд. x и y цветом color****************************************************************
void lcd_pset(u08 x , u08 y , ui16 color) { lcd_wrcmd16(0xEF90); lcd_wrcmd16(0x0504); lcd_wrcmd16(0x0800+y); lcd_wrcmd16(0x0A00+x); lcd_wrdat16(color);
} //******************************************************************************** ****************** void lcd_circ(u08 xcenter, u08 ycenter, u08 rad, ui16 color) { si16 tswitch,y1,x1 = 0; u08 d;
d = ycenter - xcenter; y1 = rad; tswitch = 3 - 2 * rad; while (x1 <= y1) { lcd_pset(xcenter + x1, ycenter + y1, color); lcd_pset(xcenter + x1, ycenter - y1, color); lcd_pset(xcenter - x1, ycenter + y1, color); lcd_pset(xcenter - x1, ycenter - y1, color); lcd_pset(ycenter + y1 - d, ycenter + x1, color); lcd_pset(ycenter + y1 - d, ycenter - x1, color); lcd_pset(ycenter - y1 - d, ycenter + x1, color); lcd_pset(ycenter - y1 - d, ycenter - x1, color);
if (tswitch < 0) tswitch += (4 * x1 + 6); else { tswitch += (4 * (x1 - y1) + 10); y1--; } x1++; } }
//******************************************************************************** ****************** void lcd_line(u08 x1,u08 y1,u08 x2,u08 y2,ui16 color) {
si16 x,y,d,dx,dy,i,i1,i2,kx,ky; s08 flag;
dx = x2 - x1; dy = y2 - y1; if (dx == 0 && dy == 0) lcd_pset(x1, y1, color); else { kx = 1; ky = 1; if( dx < 0 ) { dx = -dx; kx = -1; } else if(dx == 0) kx = 0; if(dy < 0) { dy = -dy; ky = -1; } if(dx < dy) { flag = 0; d = dx; dx = dy; dy = d; } else flag = 1; i1 = dy + dy; d = i1 - dx; i2 = d - dx; x = x1; y = y1;
for(i=0; i < dx; i++) { lcd_pset(x, y, color); if(flag) x += kx; else y += ky; if( d < 0 ) d += i1; else { d += i2; if(flag) y += ky; else x += kx; } } lcd_pset(x, y, color); } }
//******************************************************* Прямоугольник ******************************* void lcd_rect(u08 x, u08 y, u08 x1, u08 y1,ui16 color) { lcd_line (x,y,x,y1,color); lcd_line (x,y,x1,y,color); lcd_line (x,y1,x1,y1,color); lcd_line (x1,y,x1,y1,color); }
//******************************************************* Pакрашенный прямоугольник ***************************** void lcd_fillrect(u08 x, u08 y, u08 x1, u08 y1,ui16 color) { u08 i; for (i=y; i<=y1; i++) lcd_line(x,i,x1,i,color); }
//******************************************************вывод строка из flash****************************** void lcd_str_fl(u08 flash*str,u08 font,ui16 color) { while ( *str !='\0') { put_char(*str++,font,color); } } //********************** void ram_to_lcd(unsigned char*str,u08 font,ui16 color) { while (*str !='\0') { put_char(*str++,font,color); } } //******************************************************вывод строка из ram****************************** void lcd_str_ram(ui16 var, u08 font,ui16 color) { sprintf(buffer ,"%-u",var); ram_to_lcd(buffer,font,color); } //******************************************************вывод картинки********************************** Цитата void WDT_off(void) { /* reset WDT */ _WDR(); /* Write logical one to WDTOE and WDE */ WDTCR |= (1<<WDTOE) | (1<<WDE); /* Turn off WDT */ WDTCR = 0x00; } CodeVision это не проглотит. Переделывать не собираюсь, чтобы не гадать потом - само по себе не сработало или коряво переделал. Если знаете как это написать в CodeVision, например чем заменить _WDR(); , напишите.
|
|
|
|
|
Aug 31 2008, 21:16
|
Гуру
     
Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882

|
Цитата(Зверюга @ Sep 1 2008, 01:39)  Господа, мне остается только привести здесь текст библиотеки Столь большие по объему исходники вообще-то в виде аттачей прикладывать принято. Цитата(Зверюга @ Sep 1 2008, 01:39)  и попросить вас взглянуть, чего вне есть потенциально опасного в плане ресета, может конфликты какие? Цитата //******************************************************вывод строка из ram****************************** void lcd_str_ram(ui16 var, u08 font,ui16 color) { sprintf(buffer ,"%-u",var); ram_to_lcd(buffer,font,color); } Наивероятная причина выделена. Возможные последствия применения sprintf - наползание стека на данные.
|
|
|
|
|
Sep 1 2008, 03:17
|
Местный
  
Группа: Свой
Сообщений: 413
Регистрация: 15-12-06
Пользователь №: 23 563

|
Вы не правы. Это наименее вероятная причина. Функция lcd_pset так же вызывает ресет, а она не подразумевает вызов sprintf. Комментированием строк в библиотеку мной установлено, что если в во всех функциях закомментировать вызов функции spi_send() то ресет не происходит. То есть причина в этой функции. Код void spi_send(u08 dat) {
#asm
ld r26,y sbi 0xd,7 out 0xf,r26 SPI_SEND_2: sbis 0xe,7 rjmp SPI_SEND_2 sbi 0x18,2 #endasm
} Ваши предложения?
|
|
|
|
|
Sep 1 2008, 17:23
|

Местный
  
Группа: Участник
Сообщений: 355
Регистрация: 27-03-07
Из: Україна, Чуднів
Пользователь №: 26 530

|
Цитата(Зверюга @ Aug 31 2008, 22:39)  CodeVision это не проглотит. Переделывать не собираюсь, чтобы не гадать потом - само по себе не сработало или коряво переделал. Если знаете как это написать в CodeVision, например чем заменить _WDR(); , напишите. Это простая асмовская команда WDR(Watchdog Reset). и ещё, трудно сказать, а без прерываний выводится ведь на ура? Посмотрите ассемблерный листинг сгенерированный компилятором - может там чтото заметите. и ещё, в разделе для АВР люди пользуются дисплеями от сименса (тема есть такая, довольно популярная), может стоит там спросить?
--------------------
нельзя недооценивать предсказуемость глупости
|
|
|
|
|
Sep 2 2008, 05:20
|
Местный
  
Группа: Свой
Сообщений: 413
Регистрация: 15-12-06
Пользователь №: 23 563

|
Цитата замените для чистоты эксперимента функцию на асме - на сишный эквивалент, тем более компилятор вам сгенерит код ничуть не хуже... Я "консерваториев не заканчивал", не могли бы вы выразить свою мысль в Сишном коде?
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|