Цифровой компас

Схемы и устройства на микроконтроллерах. Обсуждение.

Цифровой компас

Сообщение mas_nk » 27 мар 2009, 10:23

Здравствуйте. Имеется задумка сделать цифровой компас на микросхемах HoneyWell.
Три датчика магнитного поля X,Y - hmc1022 и Z-hmc1021Z. В качетсве компенсации угла наклона использовать ADXL213. Точность высокая не нужна поэтому использую встроенный АЦП ATmega16. Результат вывожу на компьютер по rs232. Программу пишу в CodeVision. Датчики пока заказываю. В "Базе Электроники" комплект обошелся в 2200 руб.
Схему делаю по DataSheet-у.
mas_nk
 
Сообщения: 19
Зарегистрирован: 26 мар 2009, 15:18

Цифровой компас

Сообщение mas_nk » 27 мар 2009, 13:29

Вот что у меня получилось. Т.к. ADXL213 имеет температурный дрейф,
добавил датчик температуры DS18S20.
Вот с выходом акселлерометра (ШИМ) не могу разобраться.
Для вычесления азимута необходимо измерять угол наклона в двух плоскостях x и y.
Вот ссылка на DataSheet
http://www.ssec.honeywell.com/magnetic/ ... mc1055.pdf
mas_nk
 
Сообщения: 19
Зарегистрирован: 26 мар 2009, 15:18

Цифровой компас

Сообщение mas_nk » 27 мар 2009, 13:38

Код: Выделить всё
#include <mega16.h>

// 1 Wire Bus functions
#asm
   .equ __w1_port=0x18 ;PORTB
   .equ __w1_bit=0
#endasm
#include <1wire.h>

// DS1820 Temperature Sensor functions
#include <ds1820.h>
#define MAX_DEVICES 8
#define Rising   1
#define Falling 0
#include <delay.h>


/* DS1820/DS18S20 devices ROM code storage area */
unsigned char rom_code[MAX_DEVICES][9],CurrentEdge;
unsigned int temp,a1,a2,a3,i,devices,T1=0, T2=0, PreviousTime, CurrentTime;   // температура, выходы с датчиков соотвественно x,y,z
char accel=0; //угол

// Standard Input/Output functions
#include <stdio.h>

// Timer 1 input capture interrupt service routine
interrupt [TIM1_CAPT] void timer1_capt_isr(void)
{                   

   if (CurrentEdge == Rising){
      
      CurrentTime = ICR1L;
      TCCR1B = 0b00000001;   // Set Falling edge
      CurrentEdge = Falling;
      
      if (CurrentTime>PreviousTime) T2=CurrentTime-PreviousTime;
      else T2 = 65535-PreviousTime+CurrentTime;
      PreviousTime=CurrentTime;
   } else {               // if Edge Falling
      
      CurrentTime = ICR1L;    
      TCCR1B = 0b01000001;   // set Rising edge
      CurrentEdge = Rising;
      
      if (CurrentTime>PreviousTime) T1= CurrentTime-PreviousTime;
      else T1= 65535-PreviousTime+CurrentTime;
      PreviousTime=CurrentTime;
// Place your code here

}



#define ADC_VREF_TYPE 0xC0
void init_avr();


// Read the AD conversion result
unsigned int read_adc(unsigned char adc_input)
{
ADMUX=adc_input | (ADC_VREF_TYPE & 0xff);
// Delay needed for the stabilization of the ADC input voltage
delay_us(10);
// Start the AD conversion
ADCSRA|=0x40;
// Wait for the AD conversion to complete
while ((ADCSRA & 0x10)==0);
ADCSRA|=0x10;
return ADCW;
}

// Declare your global variables here

void main(void)
{
 init_avr();

devices=w1_search(0xf0,rom_code);   
   
while (1)
     {
       i=0;
         temp=ds1820_temperature_10(&rom_code[i][0]);
       
         printf("t=%i.%u\xf8C\n\r",temp/10,temp%10);
         
      PORTC.0=0;                 //set\reset   сброс датчиков перед ацп
       delay_ms(1);
        PORTC.0=1;

     
      a1=read_adc(1);
       printf("a1=%d",a1);
        putchar(0x0D);
      a2=read_adc(2);
        printf("a2=%d",a2);
        putchar(0x0D);
      a3=read_adc(3);
       printf("a3=%d",a3);
        putchar(0x0D);
     
       accel = accel + (T1/(T1+T2)-0.546)/0.125;
      // Place your code here
           
      };
     
}       
void init_avr(void)
       {
// Declare your local variables here

// Input/Output Ports initialization
// Port A initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTA=0x00;
DDRA=0x00;

// Port B initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTB=0x00;
DDRB=0x00;

// Port C initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTC=0x01;
DDRC=0xFF;


// Port D initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTD=0x00;
DDRD=0x00;

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: Timer 0 Stopped
// Mode: Normal top=FFh
// OC0 output: Disconnected
TCCR0=0x00;
TCNT0=0x00;
OCR0=0x00;

// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: 4000,000 kHz
// Mode: Normal top=FFFFh
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: On
// Input Capture on Rising Edge
// Timer 1 Overflow Interrupt: Off
// Input Capture Interrupt: On
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=0x00;
TCCR1B=0xC1;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;

// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: Timer 2 Stopped
// Mode: Normal top=FFh
// OC2 output: Disconnected
ASSR=0x00;
TCCR2=0x00;
TCNT2=0x00;
OCR2=0x00;

// External Interrupt(s) initialization
// INT0: Off
// INT1: Off
// INT2: Off
MCUCR=0x00;
MCUCSR=0x00;

// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x20;

// USART initialization
// Communication Parameters: 8 Data, 1 Stop, No Parity
// USART Receiver: Off
// USART Transmitter: On
// USART Mode: Asynchronous
// USART Baud Rate: 9600
UCSRA=0x00;
UCSRB=0x08;
UCSRC=0x86;
UBRRH=0x00;
UBRRL=0x19;

// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
SFIOR=0x00;

// ADC initialization
// ADC Clock frequency: 125,000 kHz
// ADC Voltage Reference: Int., cap. on AREF
// ADC Auto Trigger Source: None
ADMUX=ADC_VREF_TYPE & 0xff;
ADCSRA=0x85;

// 1 Wire Bus initialization
w1_init();

// Global enable interrupts
#asm("sei")
}
mas_nk
 
Сообщения: 19
Зарегистрирован: 26 мар 2009, 15:18

Re: Цифровой компас

Сообщение Radioded » 28 мар 2009, 17:52

Здравствуйте, mas_nk!
Работал когда-то с ШИМ на ATmega32, считывал показания датчика ускорения ADXL202, вот тут: http://radioded.ru/index.php?option=com ... &Itemid=49 .Как я понял,Вы это видели. А в чем проблема, что именно не работает, вообще никаких данных не можете с ШИМ? Вроде, по коду все ОК, и прерывание включено и т.д. и т.п. Единственное, что может быть, так это, то что Вы используете другой чип, не ATmega32, возможно надо будет писать другие значения в регистры TCCR1B... И как я понял, у вас неправильно настроен таймер1, при создании проекта:
Код: Выделить всё
// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: 4000,000 kHz
// Mode: Normal top=FFFFh
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: On
// Input Capture on Rising Edge
// Timer 1 Overflow Interrupt: Off
// Input Capture Interrupt: On
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=0x00;
TCCR1B=0xC1;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;


Попробуйте писать код без вставок CodeVisionAVR, или возьмите мой исходник под WinAVR.
Аватара пользователя
Radioded
Site Admin
 
Сообщения: 180
Зарегистрирован: 07 ноя 2008, 02:47
Откуда: Москва

Цифровой компас

Сообщение mas_nk » 29 мар 2009, 08:22

Radioded, пожалуйста прокоментируйте подробно ваш код, чтобы мне разобраться и можно было настроить таймер и написать код под мой чип.
Timer 1 input capture interrupt service routine
interrupt [TIM1_CAPT] void timer1_capt_isr(void)
{

if (CurrentEdge == Rising){

CurrentTime = ICR1;
TCCR1B = 0b00000001; // Set Falling edge
CurrentEdge = Falling;

if (CurrentTime>PreviousTime) T2=CurrentTime-PreviousTime;
else T2 = 65535-PreviousTime+CurrentTime;
PreviousTime=CurrentTime;
} else { // if Edge Falling

CurrentTime = ICR1;
TCCR1B = 0b01000001; // set Rising edge
CurrentEdge = Rising;

if (CurrentTime>PreviousTime) T1= CurrentTime-PreviousTime;
else T1= 65535-PreviousTime+CurrentTime;
PreviousTime=CurrentTime;
// Place your code here
mas_nk
 
Сообщения: 19
Зарегистрирован: 26 мар 2009, 15:18

Re: Цифровой компас

Сообщение Radioded » 29 мар 2009, 15:31

Вот добавил комментарии, они напечатаны жирным шрифтом:
Timer 1 input capture interrupt service routine
interrupt [TIM1_CAPT] void timer1_capt_isr(void) // -- прерывание по изменению уровня на ножке Input Capture Pin
{

if (CurrentEdge == Rising){ // -- этот кусок кода выполняется, если прерывание было по нарастающему фронту, переменнаю CurrentEdge - является для нас своеобразным флагом, показывающим по какому фронту произошло прерывание.

CurrentTime = ICR1; // -- считываем в переменную CurrentTime время возникновения нарастающего фронта
TCCR1B = 0b00000001; // Set Falling edge // -- устанавливаем прерывание по спадающему фронту чтобы измерить длительность ШИМ импульса
CurrentEdge = Falling; // -- устанавливаем флаг (для себя), что следующий захват по ниспадающему фронту

if (CurrentTime>PreviousTime) T2=CurrentTime-PreviousTime; // -- В этих строках идет вычисление длительности ШИМ "1" в тактах МК
else T2 = 65535-PreviousTime+CurrentTime; // -- считаем так, если значение таймера перевалило за значение 65535 т.е. пошел считать с нуля
PreviousTime=CurrentTime;
} else { // if Edge Falling //-- этот кусок кода будет выполнятся, если прерывание было по ниспадающему фронту, далее всё аналогично, как было выше

CurrentTime = ICR1;
TCCR1B = 0b01000001; // set Rising edge
CurrentEdge = Rising;

if (CurrentTime>PreviousTime) T1= CurrentTime-PreviousTime;
else T1= 65535-PreviousTime+CurrentTime;
PreviousTime=CurrentTime;
// Place your code here
}
Аватара пользователя
Radioded
Site Admin
 
Сообщения: 180
Зарегистрирован: 07 ноя 2008, 02:47
Откуда: Москва

Цифровой компас

Сообщение mas_nk » 30 мар 2009, 12:12

Спасибо за коментарии. Уще вопрос, в коде
accel = accel + ((double)T1/((double)T1+(double)T2)-0.546)/0.125; // 0.546
как вычислить заполнение ШИМ кадра (0.546).
mas_nk
 
Сообщения: 19
Зарегистрирован: 26 мар 2009, 15:18

Re: Цифровой компас

Сообщение Radioded » 30 мар 2009, 17:45

На самом деле число 0.546 - это поправка, должно стоять 0.5 , но в даташите указано, что это коэффициент надо подбирать опытным путём для большей точности. При значении 0.5 данные с датчика немного не соответствовали действительности. А так ускорение считается по такой формуле, которую взял из даташита на датчик ADXL202:

Acceleration(g) = (T1/T2 – 0.5)/12.5%

Советую заглянуть в даташит на ваш датчик, возможно там есть различия.
Аватара пользователя
Radioded
Site Admin
 
Сообщения: 180
Зарегистрирован: 07 ноя 2008, 02:47
Откуда: Москва

Цифровой компас

Сообщение mas_nk » 02 апр 2009, 10:29

Radioded, у вас на фотографии акселерометра подключена флэш карта,
не могли бы вы описать схему подключения, алгоритм записи-чтения, если можно на примере.
mas_nk
 
Сообщения: 19
Зарегистрирован: 26 мар 2009, 15:18

Re: Цифровой компас

Сообщение Radioded » 02 апр 2009, 12:08

Да, это карточка MMC, поигрался с ней. Читал блоками по 512 байт, с FAT не стал заморачиваться. Она в моей конструкции не использовалась, эту плату я изначально использовал как макетную. Исходники для работы с картами памяти SD / MMC я выкладывал здесь: http://radioded.ru/forum/viewtopic.php?f=7&t=34.
Аватара пользователя
Radioded
Site Admin
 
Сообщения: 180
Зарегистрирован: 07 ноя 2008, 02:47
Откуда: Москва

Цифровой компас

Сообщение mas_nk » 03 апр 2009, 05:23

Radioded, посоветуй как лучше сделать коммутацию, с акселлерометра два выхода ШИМ X и Y, а в mega16 один вход таймера захвата?
mas_nk
 
Сообщения: 19
Зарегистрирован: 26 мар 2009, 15:18

Re: Цифровой компас

Сообщение Radioded » 03 апр 2009, 13:56

Можно вместо ICP, использовать ноги INT0 и INT1 (в DIP корпусе это 16 и 17 ноги). И по возникновению прерывания считывать значения счетчика TCNT1 и производить вычисления периодов лог. "1" в ШИМ, а дальше простая арифметика.
Важно, не забывать переключать режимы прерываний на этих ножках т.е. ставить то по спадающему фронту то по нарастающему фронту, чтобы захватывать моменты изменения сигнала на этих ножках.
Аватара пользователя
Radioded
Site Admin
 
Сообщения: 180
Зарегистрирован: 07 ноя 2008, 02:47
Откуда: Москва

След.

Вернуться в Схемы, устройства и проекты на микроконтроллерах



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

Зарегистрированные пользователи: нет зарегистрированных пользователей

cron