Winarv И Int32

Программирование микроконтроллеров AVR, PIC, ARM.
Разработка и изготовление печатных плат для модулей.

Winarv И Int32

Сообщение kolos450 » 17 июн 2010, 16:12

Доброго времени суток. Нужно сделать быстрый вольтметр сетевого напряжения для отслеживания всяких падений. Для этого, как я понимаю, нужно выбрать из периода некоторое количество мгновенных значений напряжения, сложить их квадраты и извлечь из этого корень. Ну или, как вариант, использовать что-то на подобие ad536, которых просто нет в нашем городе, поэтому остановился на первом.

В процессе отладки программы в протеусе(atmega32) столкнулся с тем, что программа сбрасывается при выполнении с 32-битными числами таких операций, как остаток от деления, деление и, наверняка, что-нибудь ещё. Вместо команды "_delay_loop_2(5000)" почему-то также происходит сброс.

Кроме того, мне не удалось завести таймер1 - устанавливаю коэффициенты в TCCR1B, а регистр TCNT1 не увеличивает своего содержания.

Исходник:
Код: Выделить всё
#define   __AVR_ATmega32__   1
#define OSCSPEED   8000000      /* in Hz */

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>
#include <avr/iom32.h>
#include <avr/delay.h>
#include <avr/wdt.h>
#include <math.h>
#include <stdint.h>

void resetDisplay()
{
   PORTB &= 0x80;
   PORTD &= 0x83;
   PORTB |= 0x1F;
   PORTD |= 0x70;
}

void showDigit(long int* digit)
{
   switch(*digit)
   {
      case 0:
         PORTB &= 0xF2;
         PORTD &= 0x8F;
         break;
      case 1:
         PORTB &= 0xF7;
         PORTD &= 0xBF;
         break;
      case 2:
         PORTB &= 0xF8;
         PORTD &= 0x9F;
         break;
      case 3:
         PORTB &= 0xF1;
         PORTD &= 0x9F;
         break;
      case 4:
         PORTB &= 0xF5;
         PORTD &= 0xAF;
         break;
      case 5:
         PORTB &= 0xF1;
         PORTD &= 0xCF;
         break;
      case 6:
         PORTB &= 0xF0;
         PORTD &= 0xCF;
         break;
      case 7:
         PORTB &= 0xF7;
         PORTD &= 0x8F;
         break;
      case 8:
         PORTB &= 0xF0;
         PORTD &= 0x8F;
         break;
      case 9:
         PORTB &= 0xF1;
         PORTD &= 0x8F;
         break;
   }
}

int wADC = 0;
long int adcData;
int adcFlag = 1;
unsigned int timer = 0;

ISR(SIG_OVERFLOW1)
{
   PORTC = 1;
   adcFlag = 0;
   
   wADC = sqrt(adcData);
   adcData = 0;
   TCNT1 = 0xFD8F;   // 64911
   
   adcFlag = 1;
}

ISR(SIG_ADC)
{
   PORTC = 1;

   if(adcFlag)
   {
      long int adcTemp = ADCW;
      adcTemp *= adcTemp;
      adcData += adcTemp;
   }
   
   ADCSRA |= 0x50;   // 0b01010000
}

int main (void)
{
   adcData = 0;

   PORTB = 0x0;
   PORTC = 0x0;
   PORTD = 0x0;

   DDRB = 0x7F;   // 0b01111111
   DDRC = 0x1;   // 0b00000001
   DDRD = 0x7C;   // 0b01111100
   
   ADMUX = 0;
   ADCSRA = 0xCD;   // 0b11001101
   
   TCCR1A = 0;
   TCCR1B = 7;   // 0b00000111
   TCNT1 = 0xFD8F;   // 64911
   TIFR = 0;
   TIMSK = 0x80;   // 0b10000000
   GIMSK = 0;
   
   sei();
   
   while(1)
   {      
      long int num = wADC;
      long int digit = 0;
      num /= 10.3;
      
      for(int i = 0; i < 2; i++)
      {
         timer = TCNT1;
         resetDisplay();
         
         if(i == 0) PORTB |= 0x40;
         else PORTB |= 0x20;
         
         digit = num % 10;
         num /= 10;
         
         showDigit(&digit);
         
         //_delay_loop_2(5000);
      }
      
      resetDisplay();
      wdt_reset();
   }
}



Помогите, пожалуйста, решить проблемы!

proteus.rar
Проект Протеуса
(29.94 КиБ) Скачиваний: 0
kolos450
 
Сообщения: 3
Зарегистрирован: 17 июн 2010, 16:08
Откуда: Харьков
прог. языки: C/C++, С#, ASP, SQL, PHP, JS

Re: Winarv И Int32

Сообщение Vooon » 17 июн 2010, 17:13

Это:
Код: Выделить всё
#define   __AVR_ATmega32__   1
#define OSCSPEED   8000000      /* in Hz */


Сразу выкинуть! -std=gnu99 -mmcu=atmega32 -DF_CPU=8000000UL

Код: Выделить всё
#include <avr/interrupt.h>
-#include <avr/signal.h>
-#include <avr/iom32.h>
-#include <avr/delay.h>
+#include <util/delay.h>
+#include <stdint.h>


showDigit лучше изменить, использовать таблицу:
Код: Выделить всё
#define ARRAY_SIZE(array) ( sizeof(array)/sizeof(array[0]) )
typedef struct {
    uint8_t portb;
    uint8_t portd;
} digit_t;

digit_t digit_table[] = {
    [0] = { 0xf2, 0x8f },
    ...
};

void showDigit(uint8_t digit)
{
    if (digit > ARRAY_SIZE(digit_table))
        return;
    digit_t *ptr = digit_table+digit;
    PORTB &= ptr->portb;
    PORTD &= ptr->portd;
}


Инициализировать так регистры крайне неудобно для сопровождения.
Лучше писать так:
Код: Выделить всё
// TIM 1 Config:
//   Overflow irq
//   Freq: xxx
TCNT1 = 64911;
TCCR1A = _BV(bita)|_BV(bitb)|_BV(bitc);
TCCR1B = _BV(bita)|_BV(bitb)|_BV(bitc);
TIMSK |= _BV(OCIE1);


А пока мне разбираться в этом месиве совершенно не хочется.

Добавлено спустя 5 минут 18 секунд:
И потом, у первого таймера есть прерывания по совпадению и CTC Mode, зачем писать через переполнения?
Linux user | Firefox user
Аватара пользователя
Vooon
Site Admin
 
Сообщения: 3339
Зарегистрирован: 09 фев 2006, 15:36
Откуда: Москва
Skype: vooon341
прог. языки: Python, C, Bash, JavaScript, C++, PHP
ФИО: Владимир Ермаков

Re: Winarv И Int32

Сообщение boez » 17 июн 2010, 17:52

Да, а программа сбрасывается может быть оттого, что ватчдог активен?
boez
 
Сообщения: 1981
Зарегистрирован: 27 авг 2008, 10:45
Откуда: Харьков
прог. языки: С/С++

Re: Winarv И Int32

Сообщение kolos450 » 17 июн 2010, 22:10

Vooon, спасибо, после выполнения ваших рекомендаций всё как-то само сразу заработало.

В итоге что-то такое получилось, может пригодится:
Код: Выделить всё
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <avr/wdt.h>
#include <math.h>
#include <stdint.h>

#define ARRAY_SIZE(array) ( sizeof(array)/sizeof(array[0]) )

typedef struct {
    uint8_t portb;
    uint8_t portd;
} digit_t;

digit_t digit_table[] = {
    [0] = { 0xf2, 0x8f },
    [1] = { 0xf7, 0xbf },
    [2] = { 0xf8, 0x9f },
    [3] = { 0xf1, 0x9f },
    [4] = { 0xf5, 0xaf },
    [5] = { 0xf1, 0xcf },
    [6] = { 0xf0, 0xcf },
    [7] = { 0xf7, 0x8f },
    [8] = { 0xf0, 0x8f },
    [9] = { 0xf1, 0x8f }
};

void showDigit(uint8_t digit)
{
    if (digit > ARRAY_SIZE(digit_table)) return;
    digit_t *ptr = digit_table + digit;
    PORTB &= ptr->portb;
    PORTD &= ptr->portd;
}

void resetDisplay()
{
   PORTB &= 0x80;
   PORTD &= 0x83;
   PORTB |= 0x1F;
   PORTD |= 0x70;
}

int wADC = 0;
long int adcData;
int adcFlag = 1;
unsigned int timer = 0;

ISR(SIG_OUTPUT_COMPARE1A)
{
   PORTC = 1;
   adcFlag = 0;
   
   wADC = sqrt(adcData);
   adcData = 0;
   
   adcFlag = 1;
}

void start_config()
{
   // Ports Config
   PORTB = 0x0;
   PORTC = 0x0;
   PORTD = 0x0;
   DDRB = 0x7F;   // 0b01111111
   DDRC = 0x1;      // 0b00000001
   DDRD = 0x7C;   // 0b01111100
   
   // ADC Config
   //   Freq:   8M/64 = 125000
   //   Pin:    PA0
   //    Int:   true
   //   Start:   true
   //    Enabl:   true
   ADMUX = 0;
   ADCSRA = _BV(ADPS1)|_BV(ADPS2)|_BV(ADIE)|_BV(ADSC)|_BV(ADEN);
   
   // Timer1 Config
   //   Freq:   8M/256 = 31250
   //   OCR1A: 625
   //    Int:   OCR1A
   //    CTC:   true
   TCCR1A = 0;
   TCCR1B = _BV(WGM12)|_BV(CS12);
   TCNT1 = 0;
   TIFR = 0;
   TIMSK = _BV(OCIE1A);
   GIMSK = 0;
   OCR1A = 625;
   
   // RS232 Config
   //   Freq:   9600
   unsigned int BaudRate = 51;
   UBRRH = (unsigned char) (BaudRate>>8);
   UBRRL = (unsigned char) BaudRate;
   UCSRB |= _BV(RXEN)|_BV(TXEN);
   UCSRC |= _BV(UCSZ0)|_BV(UCSZ1)|_BV(URSEL);
   
   sei();
}

ISR(SIG_ADC)
{
   PORTC = 1;

   if(adcFlag)
   {
      long int adcTemp = ADCW;
      adcTemp *= adcTemp;
      adcData += adcTemp;
   }
   
   ADCSRA |= _BV(ADIF)|_BV(ADSC);
}

int main (void)
{
   adcData = 0;
   
   start_config();
   
   while(1)
   {
      if( (UCSRA & _BV(RXCIE)) && (UDR == 'z') )
      {         
         while (!(UCSRA & _BV(UDRE)));
         UDR = (unsigned char) (wADC>>8);
         while (!(UCSRA & _BV(UDRE)));
         UDR = (unsigned char) wADC;
      }
   
      long int num = wADC;
      uint8_t digit = 0;
      num /= 50;
      
      for(int i = 0; i < 2; i++)
      {
         timer = TCNT1;
         resetDisplay();
         
         if(i == 0) PORTB |= 0x40;
         else PORTB |= 0x20;
         
         digit = num % 10;
         num /= 10;
         
         showDigit(digit);
         
         _delay_loop_2(5000);
      }
      
      resetDisplay();
      wdt_reset();
   }
}


Написал софтину для мониторинга сети с помощью этого устройства. Отображает текущее состояние, каждые 5 минут дописывает в файл поминутное состояние. Можно поставить исключения (ниже или выше значений), записывает подробнее, каждые ~20ms. Строит график за день (поминутное состояние). Исходник на C# (используются xCharts, xGauge) в приложении.
Вложения
uTester.rar
(25.34 КиБ) Скачиваний: 0
Последний раз редактировалось Vooon 17 июн 2010, 22:20, всего редактировалось 1 раз.
Причина: [code=cpp]!!!
kolos450
 
Сообщения: 3
Зарегистрирован: 17 июн 2010, 16:08
Откуда: Харьков
прог. языки: C/C++, С#, ASP, SQL, PHP, JS

Re: Winarv И Int32

Сообщение avr123.nm.ru » 17 июн 2010, 22:29

Отлично ! Спасибо. Желательно добавить детектор пиковых значений и записывать зашкаливания. А то в нутри минуты может быть расколбас был в сети а мы не заметим.
Читайте !
Аватара пользователя
avr123.nm.ru
отсылающий читать курс
 
Сообщения: 14195
Зарегистрирован: 06 ноя 2005, 04:18
Откуда: Москва

Re: Winarv И Int32

Сообщение kolos450 » 17 июн 2010, 22:36

avr123.nm.ru писал(а):Желательно добавить детектор пиковых значений и записывать зашкаливания. А то в нутри минуты может быть расколбас был в сети а мы не заметим.

kolos450 писал(а):Можно поставить исключения (ниже или выше заданных значений), записывает подробнее, каждые ~20ms.

Я имел в виду, что это уже реализовано.
kolos450
 
Сообщения: 3
Зарегистрирован: 17 июн 2010, 16:08
Откуда: Харьков
прог. языки: C/C++, С#, ASP, SQL, PHP, JS


Вернуться в Микроконтроллеры

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 16