Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: DS18b20
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
huntero4ek
Здравствуйте. Хочется сделать небольшую программку на AT91SAM7 для получения температуры с датчика DS18b20, самому писать не хочеться) Обыскал инет и не нашел ничего полезного. Для AVR - уйма всяких исходников, а вот под ARM - ни одного. Буду очень благодарен (и думаю не только я), если кто-нибудь выложит исходный код опроса термодатчика под IAR)))
HARMHARM
Читаете это и это. Остается заменить код, который UART обслуживает.
huntero4ek
Спасибо конечно, но это опять таки программа для AVR. Думаю для Вас не составит написать программу по даташит или переделать программу, написанную под AVR, но для меня это вызывает некие трудности. Поэтому очень хотелось бы увидеть конкретную реализацию программы опроса термодатчика для AT91SAM7, которая опробована в действии) Заранее спасибо
huntero4ek
Ну если никто не хочет предоставить готовую подпрограмму, тогда вопрос:
Для опроса датчика необходимо конкретное время держать логические уровни (writebit0 - 60us и т.п.). Вопрос: каким образом лучше реализовать точное время удержания уровня, кажый раз включая таймер? У меня в проэкте уже задействованы 3 таймера из 3 (1 - управеление соннарами, другой - передача информации по радиоканалу, 3 - собственно опрос термодатчика). Спасибо
Deka
Цитата
Ну если никто не хочет предоставить готовую подпрограмму, тогда вопрос
Вам уже предоставили основу по которой можно сделать то, что Вам нужно.
Цитата
У меня в проэкте уже задействованы 3 таймера из 3
Я так понимаю, что таймеры задействованы теми кусками кода, которые Вам тоже кто-то дал специально для Вашего ARM? laugh.gif
И ещё я думаю, что Вам надо в ветку поиска разработчиков написать. Они Вам всё и увяжут. И таймеры и сонары и термодатчики!
huntero4ek
Еще раз убеждаюсь в "полезности" форумов. Принцип "научился сам - поумничаю над другими" работает исправно wink.gif Если же все так просто, то почему до сих пор никто не выложил готовый исходник опроса термодатчика под ARM? )) Под AVR люди поотзывчивее (или просто они на рынке дольше)) Ну с этим ладно. По поводу сонаров, то вы глубоко ошибаетесь - все пишу сам. Под PIC и МК51 было писать немнго приятнее. Большое спасибо за ссылки на стандартные даташит.
P.S. Если ничем дельным помочь не можете, плз, не пишите вообще.

P.P.S. И напоследок как всегда вопрос (может слишком простой, но я только учусьwink.gif):
настраиваю ногу МК на вход.
Код
#define RSON          (1<<20)
AT91F_PMC_EnablePeriphClock ( AT91C_BASE_PMC, 1 << AT91C_ID_PIOA );
AT91F_PIO_CfgInput(AT91C_BASE_PIOA, RSON);

void timer0_c_irq_handler(void)
{
    AT91PS_TC TC_pt = AT91C_BASE_TC0;
    //* Acknowledge interrupt status
    dummy = TC_pt->TC_SR;
    if(BarFlag){
          if((AT91F_PIO_GetInput( AT91C_BASE_PIOA)& RSON)==RSON){
            BarFlag=false;
            at91_IRQ0_barrier_pwm();
          }
     }
}

при этом, at91_IRQ0_barrier_pwm(); вызывается постоянно, даже в том случае, когда к RSON не подсоединено ничего.
В чем может быть проблема? Подскажите, пожалуйста
zltigo
Цитата(huntero4ek @ May 27 2009, 19:47) *
Если же все так просто, то почему до сих пор никто не выложил готовый исходник опроса термодатчика под ARM?

Значит так, мил человек, по одной простой причине, если смотреть на "проблему" не из под плинтуса, то исходники "для ARM" отличаются от исходников "для AVR", не более, чем чернила для 3 класса от чернил для 10 класса. А с DS18B20 "исходниками" вообще десятки сообщений на форуме. Только читать и учиться уметь надо. Именно по этой причне тема вообще в оффтопик перенесена.
aaarrr
Цитата(huntero4ek @ May 27 2009, 20:47) *
Под AVR люди поотзывчивее (или просто они на рынке дольше)

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

Цитата(huntero4ek @ May 27 2009, 20:47) *
при этом, at91_IRQ0_barrier_pwm(); вызывается постоянно, даже в том случае, когда к RSON не подсоединено ничего.

Когда "ничего не подключено", логический уровень на ноге какой?
huntero4ek
Цитата(aaarrr @ May 27 2009, 21:39) *
огда "ничего не подключено", логический уровень на ноге какой?

Мерял тестером - там всегда +3.3, что меня настораживает. Подскажите как правильно настроить ногу на вход.
Цитата
А с DS18B20 "исходниками" вообще десятки сообщений на форуме.

Дайте хоть 1 ссылку на эти сообщения, вместо 50 лишних слов. Я не очень силен в программировании под ARM, если для кого-то все легко, то я искренне рад за него. Надеюсь, когда научусь работать с ARM, то буду доступнее объяснять таким "чайникам" как сам. Спасибо
zltigo
Цитата(huntero4ek @ May 28 2009, 00:10) *
Дайте хоть 1 ссылку на эти сообщения

http://www.google.com/search?client=opera&...-8&oe=utf-8
Цитата
Я не очень силен в программировании под ARM....

Вы заблуждаетесь насчет не ARM-ов sad.gif.
sergeeff
Цитата(huntero4ek @ May 28 2009, 00:10) *
Мерял тестером - там всегда +3.3, что меня настораживает. Подскажите как правильно настроить ногу на вход.



Анекдот:
Приходит пациент к врачу. Говорит: "У меня проблема". Врач: "Какая?". Пациент:"Сейчас сами увидете" и начинает медленно раздеваться и аккуратнейшим образом вещи складывать на стуле. Через 15 минут, раздевшись "Видите доктор - у меня одно яичко больше другого!"
Доктор, в сердцах:"Черт возьми, да так и должно быть!"

Это я к тому, что на "висящем" входе всегда "1".
aaarrr
Цитата(huntero4ek @ May 28 2009, 01:10) *
Мерял тестером - там всегда +3.3, что меня настораживает. Подскажите как правильно настроить ногу на вход.

Прочитайте про pull-up'ы в даташите. По умолчанию они включены, а на SAM7 сопротивление у них весьма низкое, чтобы перетянуть нужен резистор <1кОм.
huntero4ek
если это норм явление, что при висячей ноге на ней лог уровень "1", то какой же уровень там будет, если подать туда "1" с внешнего устройства??
Либо ответьте сами, либо подскажите ГДЕ можно норм почитать о настраивании ноги на вход? В даташит:
Цитата
Все порты ввода-вывода PA0…PA31 (PA0…PA20 в AT91SAM7S32) полностью совместимы с 5-вольтовыми логическими уровнями и все имеют внутренние подтягивающие резисторы к VDDIO. Возможно индивидуальное отключение/подключение этих резисторов к каждому их портов с помощью контроллера портов ввода-вывода (PIO).

Совместимость с 5-вольтовыми логическими уровнями означает, что порты ввода-вывода способны формировать выходное напряжение до VDDIO и иметь входное напряжение до 5,5В. Однако, формирование на этих выводах внешнего напряжения более VDDIO с подключенными внутренними подтягивающими резисторами вызовет протекание внешнего тока через от этих выводы через подтягивающие резисторы к VDDIO. Это необходимо принимать во внимание, так как сразу после сброса по умолчанию все подтягивающие резисторы подключены к выводам портов.
aaarrr
Цитата(huntero4ek @ May 28 2009, 12:50) *
если это норм явление, что при висячей ноге на ней лог уровень "1", то какой же уровень там будет, если подать туда "1" с внешнего устройства??

"1" и будет, куда он денется?

Цитата(huntero4ek @ May 28 2009, 12:50) *
Либо ответьте сами, либо подскажите ГДЕ можно норм почитать о настраивании ноги на вход? В даташит:

В DS (родном, естественно, а не переводе) все отлично описано, что еще нужно?

Код
PIO_ODR = x;   // Переключили вывод на вход
PIO_PPUDR = x; // Запретили pull-up (если нужно)
PIO_IFER = x;  // Включили фильтр (если нужно)
PIO_PER = x;   // Перевели ногу на PIO
huntero4ek
Извините, но я не совсем понял, эти строки кода взяты из документации по IAR 4.2?
aaarrr
Нет, из головы. При чем тут IAR?
huntero4ek
Вот написал пару функций для работы с 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;
}
aaarrr
Цитата(huntero4ek @ Jun 3 2009, 02:05) *
Может есть какой-нить другой способ?

Логично было бы выставить вывод в "0" (PIO_CODR) и упрвлять направлением через PIO_OER/PIO_ODR, не трогая pull-up, который вообще должен быть внешним.
_Pasha
Цитата(huntero4ek @ Jun 3 2009, 01:05) *
Вот написал пару функций для работы с DS18B20
Код
#define IN            (1<<29) 


cranky.gif  Точно будет работать? Не надо ли (1UL << 29) ???
huntero4ek
Цитата(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 по-умолчанию включен. На шине установится высокий уровень??
aaarrr
Цитата(huntero4ek @ Jun 3 2009, 12:26) *
Т.е., сконфигурировав ногу на вход, я как бы ее освобождаю (при этом pull-up по-умолчанию включен. На шине установится высокий уровень??

Установится, куда денется.
huntero4ek
Значит подчиненный способен завалить ногу в 0 даже с внутренним pull-up резистором в МК?
Цитата
Сигнал “Чтение” : Ведущий устанавливает низкий уровень в течение 1…15 мкс. После этого подчиненный удерживает шину в низком состоянии, если желает передать лог. 0. Если необходимо передать лог. 1, то он просто освобождает линию.
aaarrr
Естественно.
huntero4ek
Никак не могу побороть проблему с генерацией временных задержек таймером.
Код
#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() вообще не вызывается, подскажите пожалуйста, в чем проблемма.
aaarrr
Цитата(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;
_Pasha
Цитата(aaarrr @ Jun 16 2009, 11:06) *
Наверное DelayFlag не объявлена как volatile.


dummy тоже надо объявить volatile
aaarrr
Цитата(_Pasha @ Jun 16 2009, 12:10) *
dummy тоже надо объявить volatile

Нет, dummy надо вообще выкинуть за ненадобностью, оставив только:
Код
TC_pt->TC_SR;


В любом случае объявлять его как volatile нет необходимости, так как этот квалификатор уже имеет TC_SR.
huntero4ek
таймеры 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 сек. Уже не знаю что и думать...
aaarrr
Цитата(huntero4ek @ Jun 17 2009, 23:12) *
прерывание должно возникать каждую мкс

И сколько тактов процессора приходится на одну микросекунду? Бедняга из прерывания не вылезает.
huntero4ek
т.е. формировать задержки порядка 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 раза дольше!
aaarrr
Цитата(huntero4ek @ Jun 17 2009, 23:48) *
т.е. формировать задержки порядка 5мкс - с помощью таймера маловероятно?

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

Цитата(huntero4ek @ Jun 17 2009, 23:48) *
нашел реализованную функцию формирования задержки

В печку ее! Чума просто, слов нет.
huntero4ek
Чет не совсем понятно что такое поллинг...
aaarrr
Опрос типа while(!(TC_SR & FLAG));
huntero4ek
Был бы очень благодарен за тестовый примерчик, с этими ...баными задержками((( Формировать интервалы порядка 1мс - без проблем, а вот порядка 1-5 мкс - никак не получается(( Предыдущую функцию (задержка формируется с помощью цикла) взял с примера, который поставляется вместе с IAR, но она работает не правильно...
aaarrr
Нет, примерчика не будет. А что касается задержек в 1-5мкс - так сделайте их тем же циклом, только откалибруйте его под свои условия.
"Неправильность" упомянутой функции заключается лишь в вычислении количества итераций - по хорошему это надо делать не в ней, а если уж делать, то во всяком случае правильно. Можете принять за отправную точку, что цикл вида while(--x); будет занимать 4 такта на итерацию при исполнении из памяти с 0WS.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.