Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Простенькая программка измерения длительности импульса.
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему
Зверюга
Здравствуйте. Подкиньте пожалуйста примерчик на CodeVision для непрерывного измерения длительности импульса контроллером AVR.

Я так прикидываю, что нужно запускать по прерыванию с пина таймер, по следующему прерыванию останавливать, читать сколько натикало, сбрасывать и вновь запускать. Дискретность - максимально возможная для таймера в atmega32.

В интернете видел только готовые очень мудрые проекты, выдрать из которых суть сложновато, да и то для IAR и WinAVR.


Спасибо.
rv3dll(lex)
Цитата(Зверюга @ Aug 30 2008, 11:37) *
Здравствуйте. Подкиньте пожалуйста примерчик на CodeVision для непрерывного измерения


так ты период померешь

если импульс гладкий ез промсечек надо после прерывания поменять в регистре статуса прерывания полярность
sKWO
Цитата(rv3dll(lex) @ Aug 30 2008, 11:00) *
если импульс гладкий ез промсечек надо после прерывания поменять в регистре статуса прерывания полярность

Ну, если и есть то можна сгладить простейшим интегратором - RC -фильтром подобрав тау под мин длит импульса.
Зверюга
бр.... оговорился... мне период и нужен.
Не значю к чему эти разговоры про фильтры, без использования прерываний а просто через PINB.х у меня все импульсы от датчика Холла фиксируются без проблем, однако хотелось бы с использованием прерываний, чтобы в период между импульсами заниматься благородными задачами, а потом по импульсу лишь считывать сколько натикало.
sKWO
запускайте таймер который имеет режим захвата во фри ран режиме. настраиваете прерывание по захвату.
выщитываете дельту между старым значением регистра захвата и новым. дальше выводите формулу связанную с тактовой частотой таймера и количеством тактов можете получить период.
Зверюга
Господа, слишком непонятно и поверхностно... Ни строчки поясняющго кода...

Я вот например запустил CodeVision Wisard и мне совершенно непонятно, как привязать внешнее прерывание к запуску и остановке таймера.

И еще - вопрос, возникший по ходу чем отличаются условия прерывания Low Level и Falling Edge? В первом случае на протяжени всего нуля будет висеть какой-то флаг? Если да, то как будет дело при Falling Edge?
sKWO
Цитата(Зверюга @ Aug 30 2008, 18:29) *
Я вот например запустил CodeVision Wisard и мне совершенно непонятно, как привязать внешнее прерывание к запуску и остановке таймера.

я тоже извиняюсь, только после именин крёсника.
Во первых про остановку таймера я ничего не говорил.
во вторых, режим захвата общеизвестен. чего уж тут обяснять.
зверюга, а при чём здесь помощник CodeVision ?
ну а как померять период?
зверюга , представьте себе ситуацию, когда Ваш счётчик сам себе считает. Ну и пускай себе считает, ведь правда? мы инициализируем периферию так, что бы обрабатывать прерывание по фронту или по спаду, как Вам уже удобно будет, на любителя. счётчик себе считает, ну и пускай.....
но тут приходит спад (Falling Edge) измеряемого сигнала и у нас возникает прерывание поскольку мы настроили прерывание по Falling Edge (ну так нам захотелось).
представим себе что счётчик считал себе и никто его не трогал. тут возникло наше прерывание. ну и тут остановки или запуска нету. в общем, когда происходит захват то состояние счётчика копируется в регистр захвата.
если это понятно, тогда обясню следующее
разница в счёте регистра захвата между первым прерыванием и вторым будет равна периоду Вашего измеряемого сигнала умноженную на частоту тактирования вашего счетчика и делённую на величину предделителя. я даже в таком состоянии немогу понять какой код Вы хотите увидеть?тут то писать нечего 07.gif
Зверюга
Боюсь Ваш метод мне не подойдет.
Объясню:
время необходимо измерять довольно точно. Ввиду этого я буду использовать 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.
sKWO
Вы глобально не разрешили прерывания.
инициализация таймера правильная, как Вы и хотели.
для КВ, непомню но вроде вот так напишите в мейне перед циклом
Код
#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 мкс. А если длительность импульса будет больше указанной величины?

А чё Вам мешает подсчитывать колличество переполнений, а в регистре захвата будете иметь значение счётчика на момент прихода следующего фронта?

о, всё придумано уже до меня ссылка.
Зверюга
Цитата
ЖКИ графический, успеет? четыре милисекунды слишком мало.


Вы правы. Разрешил глобально прерывания, ЖКИ перестал выводить на экран))) Убрал все из обработчика прерываний, даже остановил таймер (TCCR1B=0x00;) - тоже не работает. Сам факт разрешеиня прерываий не дает работать ЖКИ.

Поставил #asm cli #endasm до начала обращения к ЖКИ и #asm sei #endasm после. Выясняется, что sei вызывает перезагрузку ЖКИ...

Что делать..



Цитата
о, всё придумано уже до меня ссылка.


Прочитано до Вас. Там по-видимому для WinAVR. По крайнй мере TIMSK |= (1 << TOIE1); переваривать не хочет, TOIE1 не знает.

Так все-таки - куда точно ставить разрешение прерываний? Поставил перед void main() - ЖКИ не перегружается но и проргамма не работает...
sKWO
Цитата(Зверюга @ 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 (;;).
На моменте отладки в прерывании переполнения таймера запретите прерывания, выведите надпись, и разрешите перед выходом.
Зверюга
Спасибо конечно, но вот разрешение прерываний не дает работать ЖКИ..

Для чистоты эксперимента убрал все лишнее, убрал инициализацию таймера, убрал обработчик прерывания - просто сделал 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
sKWO
Цитата(Зверюга @ 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.

Вотчдог не включён?

Ещё, запитываете каким образом, стабилизатор и БП не слабенькие?

оф: чем отлаживаете?
Зверюга
Цитата
Как у Вас организован внешний сброс?

Чё к ресету подсоединено и как?


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

Песик выключен.
sKWO
Цитата(Зверюга @ Aug 31 2008, 18:20) *
К ресету кнопка, без резистора - никогда до этого ресеты не случались. В этом может быть причина? Включение пррываний генерирует помехи или просадки? Просто ща занят, подпаять нет времени...

да именно, об этом Вам и говорят установленные флаги.
Попробуйте сначала исключить ресет а потом уже подумаем нащёт просадок. может ещё детектор питания (БОД) не так настроен.
как появится время, резистор 1К к питанию и к ресет, конденсатор 10нан к ресету и к корпусу.
Зверюга
Подпаял резистор, конденсатор ненашел. Все равно ресетится, но уже со значением 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; (опять таки, если я правильно понял как отключить сторожа) - тот же эффект.
sKWO
Цитата(Зверюга @ 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(;;){
  }

}

В общем, код ещё на стадии разработки, но Вам для маленького направления пойдёт.
Зверюга
Вы по-моему опережаете события...
Я не решил проблему с ресетами, почитайте внимательней.
Я всего лишь добился что в MCUCSR второй бит стал равен нулю, то есть не было зафиксировано низкого уровня на ресете.

КСТАТИ! Только что взял другйо девайс на меге16. Он управляет светодиодной линейкой. Заливал MCUCSR и WDTCR в порты и по диодам смотрел состояние битов. Контроллер все время стартует с MCUCSR = 0x03, то есть с низким уровне на RESET. ОДнако включение прерываний не вызывает ресета.

Далее, собачий таймер. С чего вы взяли, что он командует парадом? Я же написал, что он у меня выключен. И по умолчанию и принудительно. Однако по другому признаку (запись в MCUCSR нулей и чтению нулей после ресета) он якобы вклчючен.

Правильно ли я его отключал? Сам он включиться может?
sKWO
Цитата(Зверюга @ 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;
}
Зверюга
ТАК, ПОХОЖЕ ГЛЮК ВСЕ ТАКИ СВЯЗАН С БИБЛИОТЕКОЙ ЖКИ

Вывел содержимое регистров на диоды портов моей отладочной платы, расставил по ходу программы маячки, выяснилось - если инициализировать дисплей, очишать его экран, то все ОК, ресета нет. Если же пытаться вывести что-то на экран, и после этого включить прерывания - происходит РЕСЕТ.
ОДНАКО, если после выведения на экран вызвать функцию библиотеки 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(); , напишите.
rezident
Цитата(Зверюга @ Sep 1 2008, 01:39) *
Господа, мне остается только привести здесь текст библиотеки
Столь большие по объему исходники вообще-то в виде аттачей прикладывать принято. twak.gif
Цитата(Зверюга @ 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 - наползание стека на данные.
Зверюга
Вы не правы. Это наименее вероятная причина. Функция 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



}


Ваши предложения?
sKWO
Цитата(Зверюга @ Aug 31 2008, 22:39) *
CodeVision это не проглотит. Переделывать не собираюсь, чтобы не гадать потом - само по себе не сработало или коряво переделал. Если знаете как это написать в CodeVision, например чем заменить _WDR(); , напишите.

Это простая асмовская команда WDR(Watchdog Reset).
и ещё, трудно сказать, а без прерываний выводится ведь на ура?
Посмотрите ассемблерный листинг сгенерированный компилятором - может там чтото заметите.
и ещё, в разделе для АВР люди пользуются дисплеями от сименса (тема есть такая, довольно популярная), может стоит там спросить?
Cyber_RAT
замените для чистоты эксперимента функцию на асме - на сишный эквивалент, тем более компилятор вам сгенерит код ничуть не хуже...
Уж по крайней мере он сам распределит регистры-память (потом в листинге сравните с вашей - что там не так)
Зверюга
Цитата
замените для чистоты эксперимента функцию на асме - на сишный эквивалент, тем более компилятор вам сгенерит код ничуть не хуже...


Я "консерваториев не заканчивал", не могли бы вы выразить свою мысль в Сишном коде?
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.