Уведомления
Очистить все

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

14 Посты
3 Пользователи
0 Likes
18.6 Тыс. Просмотры
mas_nk
(@mas_nk)
Active Member
Присоединился: 15 лет назад
Сообщения: 19
Topic starter  

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


Цитата
mas_nk
(@mas_nk)
Active Member
Присоединился: 15 лет назад
Сообщения: 19
Topic starter  

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


ОтветитьЦитата
mas_nk
(@mas_nk)
Active Member
Присоединился: 15 лет назад
Сообщения: 19
Topic starter  

#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[0]);

printf("t=%i.%uxf8Cnr",temp/10,temp%10);

PORTC.0=0; //setreset сброс датчиков перед ацп
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")
}


ОтветитьЦитата
Radioded
(@sergey)
Estimable Member Admin
Присоединился: 5 лет назад
Сообщения: 184
 

Здравствуйте, mas_nk!
Работал когда-то с ШИМ на ATmega32, считывал показания датчика ускорения ADXL202, вот тут: https://radioded.ru/index.php?option=com_content&task=view&id=83&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.


ОтветитьЦитата
mas_nk
(@mas_nk)
Active Member
Присоединился: 15 лет назад
Сообщения: 19
Topic starter  

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


ОтветитьЦитата
Radioded
(@sergey)
Estimable Member Admin
Присоединился: 5 лет назад
Сообщения: 184
 

Вот добавил комментарии, они напечатаны жирным шрифтом:
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
}


ОтветитьЦитата
mas_nk
(@mas_nk)
Active Member
Присоединился: 15 лет назад
Сообщения: 19
Topic starter  

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


ОтветитьЦитата
Radioded
(@sergey)
Estimable Member Admin
Присоединился: 5 лет назад
Сообщения: 184
 

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

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

Советую заглянуть в даташит на ваш датчик, возможно там есть различия.


ОтветитьЦитата
mas_nk
(@mas_nk)
Active Member
Присоединился: 15 лет назад
Сообщения: 19
Topic starter  

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


ОтветитьЦитата
Radioded
(@sergey)
Estimable Member Admin
Присоединился: 5 лет назад
Сообщения: 184
 

Да, это карточка MMC, поигрался с ней. Читал блоками по 512 байт, с FAT не стал заморачиваться. Она в моей конструкции не использовалась, эту плату я изначально использовал как макетную. Исходники для работы с картами памяти SD / MMC я выкладывал здесь: https://radioded.ru/forum/viewtopic.php?f=7&t=34 .


ОтветитьЦитата
mas_nk
(@mas_nk)
Active Member
Присоединился: 15 лет назад
Сообщения: 19
Topic starter  

Radioded, посоветуй как лучше сделать коммутацию, с акселлерометра два выхода ШИМ X и Y, а в mega16 один вход таймера захвата?


ОтветитьЦитата
Radioded
(@sergey)
Estimable Member Admin
Присоединился: 5 лет назад
Сообщения: 184
 

Можно вместо ICP, использовать ноги INT0 и INT1 (в DIP корпусе это 16 и 17 ноги). И по возникновению прерывания считывать значения счетчика TCNT1 и производить вычисления периодов лог. "1" в ШИМ, а дальше простая арифметика.
Важно, не забывать переключать режимы прерываний на этих ножках т.е. ставить то по спадающему фронту то по нарастающему фронту, чтобы захватывать моменты изменения сигнала на этих ножках.


ОтветитьЦитата
mas_nk
(@mas_nk)
Active Member
Присоединился: 15 лет назад
Сообщения: 19
Topic starter  

Пришли датчики, спаял схему по даташиту. Включил, ничего не работает, начал разбираться по элементам. С HMC1021, HMC1022 все стало понятно но в операционнике пришлось увеличить коэффицент умножения что бы повысить разрешающую способность.
Дальше очередь дошла до ADXL213, Rset установил 125кОм, на осцилографе сигнал меняет форму при наклонах датчика, а прога не считает правильно Т1 и Т2 вот код, подскажите в чем может быть проблема
#include <mega16.h>
#include <stdio.h>
#include <delay.h>
#include <stdlib.h>
#include <math.h>

#define Rising 1
#define Falling 0
double accel = 0;
unsigned int T1=0, T2=0, PreviousTime, CurrentTime;
unsigned char CurrentEdge;
float roll;

interrupt [TIM1_CAPT] void timer1_capt_isr(void)
{
if (CurrentEdge == Rising){

CurrentTime = ICR1L;
CurrentTime += (int)ICR1H<<8;
TCCR1B = 0b00000010; //ск/8

CurrentEdge = Falling;

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

CurrentTime = ICR1L;
CurrentTime += (int)ICR1H<<8;

TCCR1B = 0b01000010; // set Rising edge ск/8
CurrentEdge = Rising;

if (CurrentTime>PreviousTime) T1 = CurrentTime-PreviousTime;
else T1= 65535-PreviousTime+CurrentTime;
PreviousTime=CurrentTime;
}

printf("T1=%d",T1);
putchar(0x0D);
printf("T2=%d",T2);
putchar(0x0D);

accel = ((double)T1/((double)T1+(double)T2)-0.5)/0.3;

roll = asin(accel/9.81)*180/3.14; // пересчет ускорения в угол наклона и перевод из радиан в градусы

printf("accel=%f",accel);
putchar(0x0D);
printf("roll=%f",roll);
putchar(0x0D);

}

void main(void)
{
UCSRA=0x00;
UCSRB=0x18;
UCSRC="0x86;"
UBRRH=0x00;
UBRRL=0x19;
ACSR=0x80;
SFIOR=0x00;

TIMSK |= (1<< TICIE1);
TCCR1A = 0;
TCCR1B=0b11000010;

TCNT1 = 0;
CurrentEdge = Rising;

#asm("sei")

while (1) ;

delay_ms(3000);
}
Частота кварца 4 мгц, Т1 выдает в горизонтальном положении 26589, Т2=26730
в повернутом на 90гр Т1= 25851 Т2=26120 хотя на осцилографе Т1 как минимум в три раза больше Т2


ОтветитьЦитата
Lintux
(@lintux)
New Member
Присоединился: 14 лет назад
Сообщения: 1
 

Доброго времени суток!
Просмотрел код представленный mas_nk И появился вопрос вот какого рода:
1. В расчете ускорения в размерности g
accel = ((double)T1/((double)T1+(double)T2)-0.5)/0.3; откуда берется коэффициент 0,3 ?
2. Вызывает интерес ещё место в исходном коде
TCCR1B = 0b01000010;
CurrentEdge = Rising;
получается, что фильтрация входного сигнала ICP будет отключена после первого же срабатывания прерывания и далее никогда не будет применяться. Или я ошибаюсь?


ОтветитьЦитата