|
|
  |
DS18b20, Исходный код ARM |
|
|
|
Jun 2 2009, 22:05
|
Группа: Новичок
Сообщений: 11
Регистрация: 24-05-09
Пользователь №: 49 496

|
Вот написал пару функций для работы с DS18B20 Посмотрите плз, правильно ли они реализованы, в особенности меня интерисует установка "0" или "1" с помощью вкл и выкл подтягивающих резисторов. Может есть какой-нить другой способ? CODE #define IN (1<<29)
void writebit0(void){ AT91F_PIO_CfgOpendrain(AT91C_BASE_PIOA, IN);//формируем низкий уровень _delay_us(60);//по истечении 60us установит флаг DS while(!DS); AT91F_PIO_CfgPullup( AT91C_BASE_PIOA, IN);//формируем высокий уровень }
void writebit1(void){ AT91F_PIO_CfgOpendrain(AT91C_BASE_PIOA, IN);//формируем низкий уровень _delay_us(3); while(!DS); AT91F_PIO_CfgPullup( AT91C_BASE_PIOA, IN);//формируем высокий уровень _delay_us(58); while(!DS); }
void writebyte(unsigned char byte){ unsigned char i; char b; for(i=0; i<8; i++){ b = (1 << i); if (byte&b) writebit1(); else writebit0(); } }
unsigned char readbit(void){ unsigned char i; AT91F_PIO_CfgOpendrain(AT91C_BASE_PIOA, IN);//формируем низкий уровень _delay_us(10); while(!DS); AT91F_PIO_CfgPullup( AT91C_BASE_PIOA, IN);//формируем высокий уровень _delay_us(15); while(!DS); if ((AT91F_PIO_GetInput(AT91C_BASE_PIOA)& IN)==IN) i=1; else i=0; _delay_us(35); while(!DS); return i; }
signed char readbyte(void) { unsigned char i, r, read_byte; for(i=0, r=1, read_byte=0; i<8; i++){ if (readbit()) read_byte|=r; r<<=1; } return read_byte; }
Причина редактирования: Уменьшение видимого размера цитаты исходника.
|
|
|
|
|
Jun 3 2009, 08:26
|
Группа: Новичок
Сообщений: 11
Регистрация: 24-05-09
Пользователь №: 49 496

|
Цитата(aaarrr @ Jun 3 2009, 10:55)  Логично было бы выставить вывод в "0" (PIO_CODR) и упрвлять направлением через PIO_OER/PIO_ODR Т.е. так: Код unsigned char readbit(void){ unsigned char i;
AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, IN); AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, IN);//формируем низкий уровень
_delay_us(10); while(!DS); AT91F_PIO_CfgInput( AT91C_BASE_PIOA, IN);//формируем высокий уровень _delay_us(15); while(!DS); if ((AT91F_PIO_GetInput(AT91C_BASE_PIOA)& IN)==IN) i=1; else i=0; _delay_us(35); while(!DS); return i; } После установки низкого уровня ведущим (1-15us) надо "освободить шину". Т.е., сконфигурировав ногу на вход, я как бы ее освобождаю (при этом pull-up по-умолчанию включен. На шине установится высокий уровень??
|
|
|
|
|
Jun 3 2009, 08:36
|
Группа: Новичок
Сообщений: 11
Регистрация: 24-05-09
Пользователь №: 49 496

|
Значит подчиненный способен завалить ногу в 0 даже с внутренним pull-up резистором в МК? Цитата Сигнал “Чтение” : Ведущий устанавливает низкий уровень в течение 1…15 мкс. После этого подчиненный удерживает шину в низком состоянии, если желает передать лог. 0. Если необходимо передать лог. 1, то он просто освобождает линию.
|
|
|
|
|
Jun 16 2009, 07:17
|
Группа: Новичок
Сообщений: 11
Регистрация: 24-05-09
Пользователь №: 49 496

|
Никак не могу побороть проблему с генерацией временных задержек таймером. Код #define TC_CLKS_MCK8 0x1
void timer_init ( void ) { AT91F_TC_Open(AT91C_BASE_TC1,TC_CLKS_MCK8,AT91C_ID_TC1); AT91F_AIC_ConfigureIt ( AT91C_BASE_AIC, AT91C_ID_TC1, TIMER1_INTERRUPT_LEVEL,AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, timer1_c_irq_handler); AT91C_BASE_TC1->TC_IER = AT91C_TC_CPCS; } Таким образом,инкримент счетчика будет происходить 48000000/8=6000000 раз/с. сделал процедурку Код void UTIL_DelayTimeInUs(unsigned long time_us) { DelayFlag = 0; AT91C_BASE_TC1->TC_RC = 6*time_us; //умножив на шесть, получим 1 инкримент счетчика за 1мкс //умножив все это на требуемое количество мкс получим прерывание, по истечении заданного кол-ва мкс AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG; AT91F_AIC_EnableIt (AT91C_BASE_AIC, AT91C_ID_TC1); while(!DelayFlag); AT91F_AIC_DisableIt (AT91C_BASE_AIC, AT91C_ID_TC1); }
void timer1_c_irq_handler(void) { AT91PS_TC TC_pt = AT91C_BASE_TC1; unsigned int dummy; static unsigned long usCount = 0; //* Acknowledge interrupt status dummy = TC_pt->TC_SR; //* Suppress warning variable "dummy" was set but never used dummy = dummy; DelayFlag = 1; MOV_PWM(); //вызываю требуемую ф-цию } Решил прописать вызов MOV_PWM() прямо в обработчике - срабатывает моментально, не дожидаясь окончания заданного интервала ( UTIL_DelayTimeInUs(6000000); задержка должна быть 6с!). если же убрать MOV_PWM из обработчика и прописать Код UTIL_DelayTimeInUs(6000000); MOV_PWM(); то MOV_PWM() вообще не вызывается, подскажите пожалуйста, в чем проблемма.
Сообщение отредактировал huntero4ek - Jun 16 2009, 07:19
|
|
|
|
|
Jun 16 2009, 08:06
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
Цитата(huntero4ek @ Jun 16 2009, 11:17)  Решил прописать вызов MOV_PWM() прямо в обработчике - срабатывает моментально, не дожидаясь окончания заданного интервала ( UTIL_DelayTimeInUs(6000000); задержка должна быть 6с!). Видимо флаг CPCS уже взведен на момент разрешения прерываний Цитата(huntero4ek @ Jun 16 2009, 11:17)  если же убрать MOV_PWM из обработчика и прописать Код UTIL_DelayTimeInUs(6000000); MOV_PWM(); то MOV_PWM() вообще не вызывается Наверное DelayFlag не объявлена как volatile. Кроме того, дергать SWTRG при запрещенных клоках бесполезно: Код AT91F_AIC_EnableIt (AT91C_BASE_AIC, AT91C_ID_TC1); AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG;
|
|
|
|
|
Jun 16 2009, 08:13
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
Цитата(_Pasha @ Jun 16 2009, 12:10)  dummy тоже надо объявить volatile Нет, dummy надо вообще выкинуть за ненадобностью, оставив только: Код TC_pt->TC_SR; В любом случае объявлять его как volatile нет необходимости, так как этот квалификатор уже имеет TC_SR.
|
|
|
|
|
Jun 17 2009, 19:12
|
Группа: Новичок
Сообщений: 11
Регистрация: 24-05-09
Пользователь №: 49 496

|
таймеры 16-битные, поэтому переделал ф-цию: Код void UTIL_DelayTimeInUs(unsigned long time_us) { DelayFlag = 0; AT91C_BASE_TC1->TC_RC = 6; // прерывание должно возникать каждую мкс AT91F_AIC_EnableIt (AT91C_BASE_AIC, AT91C_ID_TC1); AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG; while(!DelayFlag); AT91F_AIC_DisableIt (AT91C_BASE_AIC, AT91C_ID_TC1); } Теперь пробую задавать интервал через глобальную переменную. Код void timer1_c_irq_handler(void) { AT91PS_TC TC_pt = AT91C_BASE_TC1; unsigned int dummy; static unsigned long usCount = 0;
dummy = TC_pt->TC_SR; dummy = dummy; usCount++; if(usCount == 5000000){ //вместо глоб. пер. пишу 5000000 - т.е. DelayFlag должен = 1 черех 5 сек DelayFlag = 1; usCount = 0; }else{ TC_pt->TC_CCR = AT91C_TC_SWTRG; } } проверяю - срабатывает через 15 сек. Уже не знаю что и думать...
|
|
|
|
|
Jun 17 2009, 19:48
|
Группа: Новичок
Сообщений: 11
Регистрация: 24-05-09
Пользователь №: 49 496

|
т.е. формировать задержки порядка 5мкс - с помощью таймера маловероятно? нашел реализованную функцию формирования задержки Код void UTIL_WaitTimeInUs(unsigned int mck, unsigned int time_us) { volatile unsigned int i = 0; i = (mck / 1000000) * time_us; i = i /3; UTIL_Loop(i); }
void UTIL_Loop(unsigned int loop) { while(loop--); } проверял - задержки в 2 раза дольше!
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|