|
|
  |
Проблема с функцией задержки., STM32F107 |
|
|
|
Jun 28 2016, 05:34
|
Профессионал
    
Группа: Участник
Сообщений: 1 778
Регистрация: 29-03-12
Пользователь №: 71 075

|
Переделал функции под вариант с OPEN DRAIN. CODE #define OPEN_DRAIN 1
unsigned int One_Wire_Reset(GPIO_TypeDef * GPIOx, uint16_t PINx) { #if OPEN_DRAIN unsigned int tmp; PIN_ON(GPIOx, PINx); if ((PIN_SYG(GPIOx, PINx))==0) return One_Wire_Bus_Low_Error;
PIN_OFF(GPIOx, PINx); TIM6_Delay_us(480); PIN_ON(GPIOx, PINx); TIM6_Delay_us(60);
if ((PIN_SYG(GPIOx, PINx))==0) tmp=One_Wire_Success; else tmp=One_Wire_Error_No_Echo; TIM6_Delay_us(350); return tmp; #else unsigned int tmp; PIN_IN(GPIOx, PINx); if ((PIN_SYG(GPIOx, PINx))==0) return One_Wire_Bus_Low_Error;
PIN_OUT_PP(GPIOx, PINx); PIN_OFF(GPIOx, PINx); TIM6_Delay_us(480); PIN_ON(GPIOx, PINx); PIN_IN(GPIOx, PINx); TIM6_Delay_us(60);
if ((PIN_SYG(GPIOx, PINx))==0) tmp=One_Wire_Success; else tmp=One_Wire_Error_No_Echo; TIM6_Delay_us(350); return tmp; #endif }
void One_Wire_Write_Byte(unsigned char Byte,GPIO_TypeDef * GPIOx, uint16_t PINx) { unsigned char cnt; for (cnt=0;cnt!=8;cnt++) One_Wire_Write_Bit(Byte&(1<<cnt),GPIOx, PINx); }
void One_Wire_Write_Bit (unsigned char Bit, GPIO_TypeDef * GPIOx, uint16_t PINx) { #if OPEN_DRAIN PIN_OFF(GPIOx, PINx); if (Bit==0) { TIM6_Delay_us(60); PIN_ON(GPIOx, PINx); TIM6_Delay_us(10); } else { TIM6_Delay_us(10); PIN_ON(GPIOx, PINx); TIM6_Delay_us(60); } #else PIN_OUT_PP(GPIOx, PINx); PIN_OFF(GPIOx, PINx); if (Bit==0) { //Delay_us(Time_Pulse_Delay_High); TIM6_Delay_us(60); PIN_ON(GPIOx, PINx); //Delay_us(Time_Pulse_Delay_Low) TIM6_Delay_us(10); } else { TIM6_Delay_us(10); PIN_ON(GPIOx, PINx); TIM6_Delay_us(60); } PIN_IN(GPIOx, PINx); #endif }
unsigned char One_Wire_Read_Byte(GPIO_TypeDef * GPIOx, uint16_t PINx) { unsigned char tmp=0; unsigned char cnt; for (cnt=0;cnt!=8;cnt++) if (One_Wire_Read_Bit(GPIOx, PINx)!=0) tmp|=(1<<cnt); TIM6_Delay_us(60); return tmp; }
unsigned char One_Wire_Read_Bit (GPIO_TypeDef * GPIOx, uint16_t PINx) { #if OPEN_DRAIN unsigned char tmp; PIN_OFF(GPIOx, PINx); TIM6_Delay_us(2); TIM6_Delay_us(10); if ((PIN_SYG(GPIOx, PINx))!=0) tmp = 1; else tmp = 0; TIM6_Delay_us(60); return tmp; #else unsigned char tmp; PIN_OUT_PP(GPIOx, PINx); PIN_OFF(GPIOx, PINx); TIM6_Delay_us(2); PIN_IN(GPIOx, PINx); TIM6_Delay_us(10); if ((PIN_SYG(GPIOx, PINx))!=0) tmp = 1; else tmp = 0; TIM6_Delay_us(60); return tmp; #endif } Что то не работает. Хотя на скопе вижу рисет корректный но температура и серийный номер не читаются. В старом варианте (OPEN_DRAIN 0) все работает.
Сообщение отредактировал Jenya7 - Jun 28 2016, 05:35
|
|
|
|
|
Jun 28 2016, 07:29
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
QUOTE (Jenya7 @ Jun 28 2016, 08:34)  но температура и серийный номер не читаются. В старом варианте (OPEN_DRAIN 0) все работает. Сравните: CODE PIN_OUT_PP(GPIOx, PINx); PIN_OFF(GPIOx, PINx); TIM6_Delay_us(2); PIN_IN(GPIOx, PINx); // <-- обратите внимание, тут нога перешла на ввод TIM6_Delay_us(10); if ((PIN_SYG(GPIOx, PINx))!=0) tmp = 1; } и CODE PIN_OFF(GPIOx, PINx); TIM6_Delay_us(2); TIM6_Delay_us(10); // а тут она осталась притянутой к нулю if ((PIN_SYG(GPIOx, PINx))!=0) tmp = 1;
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Jun 28 2016, 07:44
|
Профессионал
    
Группа: Участник
Сообщений: 1 778
Регистрация: 29-03-12
Пользователь №: 71 075

|
То есть нужно так? Код PIN_OFF(GPIOx, PINx); TIM6_Delay_us(2); PIN_ON(GPIOx, PINx); TIM6_Delay_us(10); // а тут она осталась притянутой к нулю if ((PIN_SYG(GPIOx, PINx))!=0) tmp = 1; Да! Работает! И даже считывает два датчика. Громадное спасибо!
Сообщение отредактировал IgorKossak - Jun 28 2016, 15:43
Причина редактирования: бездумное цитирование
|
|
|
|
|
Jun 29 2016, 18:13
|
Профессионал
    
Группа: Свой
Сообщений: 1 351
Регистрация: 21-05-10
Пользователь №: 57 439

|
Цитата(Jenya7 @ Jun 27 2016, 13:05)  Какая то ну очень странная проблема. Я сделал функцию задержки так. Код void Delay_us(uint32_t us) { uint32_t ticks = 72 * us; SysTick->LOAD = ticks; SysTick->CTRL |= 0x01; //enable while (!(SysTick->CTRL&SysTick_CTRL_COUNTFLAG_Msk)); SysTick->CTRL &= ~0x01; //disable } Я болезненно отношусь к выжиганию времени в функции задержки.
|
|
|
|
|
Jun 29 2016, 18:42
|
Профессионал
    
Группа: Свой
Сообщений: 1 241
Регистрация: 15-11-05
Из: Челябинск
Пользователь №: 10 882

|
Цитата(Tarbal @ Jun 29 2016, 23:13)  Я болезненно отношусь к выжиганию времени в функции задержки. И что с того? Если время идет на микросекунды? Для справки, на LPC21xx 48 МГц переключение контекста FreeRTOS занимает 2.2 мкс. Здесь задержки, судя по коду, 2 и 10 мкс. Стоит ли овчинка выделки? Единственое, в Delay можно добавить WFI, чтобы чуток меньше энергии кушалось.
|
|
|
|
|
Jun 30 2016, 08:48
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
QUOTE (Jenya7 @ Jun 30 2016, 11:05)  Единственное решение к которому я пришел - прерывания таймера и State Machine в прерывании. Я делал на одном прерывани таймера, использовал три модуля захвата/сравнения (Capture/Compare) и событие переполнения (UIF) таймера. Конечного автомата нет, точнее он выродился в проверку флагов CCxIF в обработчике прерывания. Получилось довольно компактно. При обмене битом первый модуль сравнения настраиваю на tLOW1, второй на tRDW, третий на tLOW0, ARR на tSLOT. Для сброса первый модуль настраиваю на tRSTL, второй на tRSTL+tPDLOW, третий на tRSTL+tRSTH, ARR на tRSTL+tRSTH. Перед запуском прерываний задаю передаваемые биты (прием = передача всех единиц) и количество битов. В прерывании уменьшаю счетчик и по достижении сигналю флаг окончания обмена. С эти же обработчиком удалось сделать и поиск устройств (там обмен идет двухбитовыми посылками). Прерывание пришлось сделать высокоприоритетным, поскольку время tRDW-tLOW1 достаточно мало. CODE // Pin_out, Pin_in - ссылки на бит линии в bitband-области. Если процессор не поддерживает bitband, то можно вставить команды управления портом. uint8_t one_wire::exchange(uint8_t in, uint_fast8_t bits) { // биты передаются начиная с младшего, принимаются в старший. Shifter = in; Bit_counter = bits; { TCritSect cs; Pin_out = 0; Timer->CR1 = 0 | 0 * (TIM_CR1_CKD & -TIM_CR1_CKD) // Dead-time clock, 0 = timer clock | 0 * TIM_CR1_ARPE // ARR buffering | 0 * (TIM_CR1_CMS & -TIM_CR1_CMS) // 0 = edge-aligned, 1...3 = center-aligned mode 1...3 | 0 * TIM_CR1_DIR // Direction, 0 = up, 1 = down | 0 * TIM_CR1_OPM // One pulse mode, 1 = stop counter at update event | 0 * TIM_CR1_URS // Update request source, 0 = any, 1 = only counter under-/overflow | 0 * TIM_CR1_UDIS // Update event generation disabling | 1 * TIM_CR1_CEN // Counter enable ; } Done_flag.wait(); return Shifter; }
void one_wire::handler() { uint_fast16_t Status = Timer->SR; Timer->SR = ~Status;
if(Status & TIM_SR_CC1IF) // bit output time { if(Shifter & (1 << 0)) Pin_out = 1; Shifter >>= 1; }
if(Status & TIM_SR_CC2IF) // bus sample time { if(Pin_in) Shifter |= (1 << 7); }
if(Status & TIM_SR_CC3IF) // bus release time Pin_out = 1;
if(Status & TIM_SR_UIF) // end of slot { if(!--Bit_counter) { Timer->CR1 = 0; // stop timer Timer->CNT = 0; OS::TISRW ISR_wrapper; Done_flag.signal_isr(); } else Pin_out = 0; // start new slot } }
bool one_wire::reset() { Mutex.lock();
Timer->ARR = T3_CLK / 2 * uint64_t(480 + 480) / (1000 * 1000); // slot time: 480 uS + 480 uS Timer->CCR1 = T3_CLK / 2 * uint64_t(480) / (1000 * 1000); // bus release: 480 uS Timer->CCR2 = T3_CLK / 2 * uint64_t(480 + 60) / (1000 * 1000); // bus sample: 480 + 60 uS Timer->CCR3 = T3_CLK / 2 * uint64_t(480 + 480) / (1000 * 1000); // dummy
if(exchange((1 << 0), 1) & (1 <<7)) { Mutex.unlock(); return false; }
Timer->ARR = T3_CLK / 2 * uint64_t(15 + 45 + 45) / (1000 * 1000); // slot time: 15 + 45 + 45 uS Timer->CCR1 = T3_CLK / 2 * uint64_t(9) / (1000 * 1000); // bit write: 9 uS Timer->CCR2 = T3_CLK / 2 * uint64_t(18) / (1000 * 1000); // bus sample: 18 uS Timer->CCR3 = T3_CLK / 2 * uint64_t(60) / (1000 * 1000); // bus release: 60 uS
return true; }
uint8_t one_wire::receive() { return exchange(0xFF, 8); }
bool one_wire::transmit(uint8_t data) { return exchange(data, 8) == data; }
Сейчас посмотрел на этот код - можно было использовать one-pulse mode. Надо будет переделать.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Jun 30 2016, 09:14
|
Знающий
   
Группа: Участник
Сообщений: 825
Регистрация: 16-04-15
Из: КЧР, Нижний Архыз
Пользователь №: 86 250

|
ТС, возьми нормальную реализацию 1-wire через таймер с DMA и не пугай людей лютым ногодрыгом! Да и вообще впреть не страдай этой фигней — ногодрыг с паузами через systick... А вдруг паузы нужно будет точные делать, а у тебя в это время прерывание какое-нибудь произойдет? Или будешь все прерывания отключать на время паузы? Кончай эту аврщину лютую!
|
|
|
|
|
Jun 30 2016, 09:30
|
Профессионал
    
Группа: Участник
Сообщений: 1 778
Регистрация: 29-03-12
Пользователь №: 71 075

|
Цитата(Сергей Борщ @ Jun 30 2016, 13:48)  Я делал на одном прерывани таймера, использовал три модуля захвата/сравнения (Capture/Compare) и событие переполнения (UIF) таймера. Конечного автомата нет, точнее он выродился в проверку флагов CCxIF в обработчике прерывания. Получилось довольно компактно. При обмене битом первый модуль сравнения настраиваю на tLOW1, второй на tRDW, третий на tLOW0, ARR на tSLOT. Для сброса первый модуль настраиваю на tRSTL, второй на tRSTL+tPDLOW, третий на tRSTL+tRSTH, ARR на tRSTL+tRSTH. Перед запуском прерываний задаю передаваемые биты (прием = передача всех единиц) и количество битов. В прерывании уменьшаю счетчик и по достижении сигналю флаг окончания обмена. С эти же обработчиком удалось сделать и поиск устройств (там обмен идет двухбитовыми посылками). Прерывание пришлось сделать высокоприоритетным, поскольку время tRDW-tLOW1 достаточно мало. CODE // Pin_out, Pin_in - ссылки на бит линии в bitband-области. Если процессор не поддерживает bitband, то можно вставить команды управления портом. uint8_t one_wire::exchange(uint8_t in, uint_fast8_t bits) { // биты передаются начиная с младшего, принимаются в старший. Shifter = in; Bit_counter = bits; { TCritSect cs; Pin_out = 0; Timer->CR1 = 0 | 0 * (TIM_CR1_CKD & -TIM_CR1_CKD) // Dead-time clock, 0 = timer clock | 0 * TIM_CR1_ARPE // ARR buffering | 0 * (TIM_CR1_CMS & -TIM_CR1_CMS) // 0 = edge-aligned, 1...3 = center-aligned mode 1...3 | 0 * TIM_CR1_DIR // Direction, 0 = up, 1 = down | 0 * TIM_CR1_OPM // One pulse mode, 1 = stop counter at update event | 0 * TIM_CR1_URS // Update request source, 0 = any, 1 = only counter under-/overflow | 0 * TIM_CR1_UDIS // Update event generation disabling | 1 * TIM_CR1_CEN // Counter enable ; } Done_flag.wait(); return Shifter; }
void one_wire::handler() { uint_fast16_t Status = Timer->SR; Timer->SR = ~Status;
if(Status & TIM_SR_CC1IF) // bit output time { if(Shifter & (1 << 0)) Pin_out = 1; Shifter >>= 1; }
if(Status & TIM_SR_CC2IF) // bus sample time { if(Pin_in) Shifter |= (1 << 7); }
if(Status & TIM_SR_CC3IF) // bus release time Pin_out = 1;
if(Status & TIM_SR_UIF) // end of slot { if(!--Bit_counter) { Timer->CR1 = 0; // stop timer Timer->CNT = 0; OS::TISRW ISR_wrapper; Done_flag.signal_isr(); } else Pin_out = 0; // start new slot } }
bool one_wire::reset() { Mutex.lock();
Timer->ARR = T3_CLK / 2 * uint64_t(480 + 480) / (1000 * 1000); // slot time: 480 uS + 480 uS Timer->CCR1 = T3_CLK / 2 * uint64_t(480) / (1000 * 1000); // bus release: 480 uS Timer->CCR2 = T3_CLK / 2 * uint64_t(480 + 60) / (1000 * 1000); // bus sample: 480 + 60 uS Timer->CCR3 = T3_CLK / 2 * uint64_t(480 + 480) / (1000 * 1000); // dummy
if(exchange((1 << 0), 1) & (1 <<7)) { Mutex.unlock(); return false; }
Timer->ARR = T3_CLK / 2 * uint64_t(15 + 45 + 45) / (1000 * 1000); // slot time: 15 + 45 + 45 uS Timer->CCR1 = T3_CLK / 2 * uint64_t(9) / (1000 * 1000); // bit write: 9 uS Timer->CCR2 = T3_CLK / 2 * uint64_t(18) / (1000 * 1000); // bus sample: 18 uS Timer->CCR3 = T3_CLK / 2 * uint64_t(60) / (1000 * 1000); // bus release: 60 uS
return true; }
uint8_t one_wire::receive() { return exchange(0xFF, 8); }
bool one_wire::transmit(uint8_t data) { return exchange(data, 8) == data; }
Сейчас посмотрел на этот код - можно было использовать one-pulse mode. Надо будет переделать. Это очень интересно. Надо попробовать. Цитата(KnightIgor @ Jun 30 2016, 14:04)  А я поставил на плату DS2484R и общаюсь с 1-WIRE по уже отлаженному I2C  . Круто. Не знал что такое есть. Может это действительно решение проблемы. Цитата(Эдди @ Jun 30 2016, 14:14)  ТС, возьми нормальную реализацию 1-wire через таймер с DMA и не пугай людей лютым ногодрыгом! Да и вообще впреть не страдай этой фигней — ногодрыг с паузами через systick... А вдруг паузы нужно будет точные делать, а у тебя в это время прерывание какое-нибудь произойдет? Или будешь все прерывания отключать на время паузы? Кончай эту аврщину лютую! Интересно. Но я так понял это для чтения одного датчика? У меня несколько на проводе висят. Вообще то аппаратное решение проблемы (DS2484) мне кажется лучше всего. Да это увеличение и удорожание платы, но с другой стороны четкая функциональность, разгрузка контроллера, грамотно буферезированный выход. Интересно какая дальнобойность у него. Мне нужно до 300 метров.
Сообщение отредактировал Jenya7 - Jun 30 2016, 09:55
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|