Отговори на тема  [ 13 мнения ] 
проблем с код 
Автор Съобщение
Ранг: Минаващ
Ранг: Минаващ

Регистриран на: Пет Юни 23, 2006 6:54 pm
Мнения: 15
Мнение проблем с код
няма ли кои да помогне с акъл как се правят сметки с числа от АЦП-то ?

идеята е число от ацп да се обработи и да се прати към лсд-то

ето докаде съм ама излизат некви странни ст-ти или нищо не излиза ,незнам какви точно променливи да ползвам и какъв формат

ф-лата която искам е АЦП_ЧИСЛО*15,685-8035,3=ХХХХmG (uskorenie)
(дат4ика дава 0,94-4,06В ->-5000mG- +5000mG)

Код:
#include <18F458.h>
//#define adc=10
#fuses HS, NOWDT, PUT ,nolvp
#use delay(clock=1000000)

#include <math.h>
#include <flex_lcd.c>   // Has modified pin list.

int16 result1;
int16 result2;
int32 accx;
float accy;



void main()
{
lcd_init();
lcd_init();
delay_ms(200);
setup_adc_ports(ALL_ANALOG);
setup_adc(ADC_CLOCK_DIV_64);

delay_ms(200);
while(true)
{

set_adc_channel(0);
   delay_us(1000);
   result1=0;
   result1 = read_adc();
   accx=0;
   accx=((result1*15.68)-8035);
   printf(lcd_putc , "\fAcc X: %06u", accx);
   
   
   delay_ms(100);
}

правилно ли "обработвам" accx (пробах с float ама пак някви лудории излизат)и какъв вид променлива трябва да бъде??? :roll:


Пет Юли 07, 2006 8:39 pm
Профил ICQ
Ранг: Форумен бог
Ранг: Форумен бог

Регистриран на: Нед Сеп 26, 2004 9:21 pm
Мнения: 30684
Местоположение: София
Мнение 
Не, не е правилно, или поне не ми изглежда така. Разви си формулта последователно, най-добре в инт, но ако имш роцесорно време може и във флоат.
Първо напрежението което получаваш :
u=read_adc()*Vref/1024 [V]
тия напрежения не знам от къде са но приемаме че сa така, което малко ме съмнява.
0 G = 2.5 V , т.е. това ти е офсета.
датчика дава 0.312 mV/mG според това което и дал, или става :

accx=(u-2.5)*0.000312 [G]

това ти е и формулата ако ползваш float. За инт трявба да я птимизираш.
За ваденето на това с printf няма да стане, ето нещо такова например :
sprintf(lcd_char,"%06lu",g ); като след това lcd_char го пращаш към дисплея. библиотекта на CCS имаше някакво дръвче май ако и подаваш променлива .... помня че го првих с последователно пращане отделните байтове на lcd_char в твоя случай


Съб Юли 08, 2006 3:39 am
Профил
Ранг: Минаващ
Ранг: Минаващ

Регистриран на: Пет Юни 23, 2006 6:54 pm
Мнения: 15
Мнение hi
намерих по проста формулка ама имам проблем с отрицателните числа
ето кода
Код:
include "C:\Documents and Settings\Administrator\Desktop\TESTOVE\ADC4.h"
#fuses HS, NOWDT, PUT ,nolvp
#use delay(clock=1000000)
  #include <float.h>
  #include <math.h>
  #include <stdio.h>
  #include <stdlib.h>

  #include <flex_lcd.c>
   
    int32 result1;
    int32 result2;
   
    float accx;
    Float accy;

    int8 i;


void main()
{

   setup_adc_ports(AN0_AN1_AN3);
   setup_adc(ADC_CLOCK_INTERNAL);
   setup_psp(PSP_DISABLED);
   setup_spi(FALSE);
   setup_wdt(WDT_OFF);
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DISABLED,0,1);
   setup_timer_3(T3_DISABLED|T3_DIV_BY_1);
   setup_comparator(NC_NC_NC_NC);
   setup_vref(FALSE);
   setup_low_volt_detect(FALSE);
   setup_oscillator(False);

   lcd_init();
lcd_init();
delay_ms(200);


while(true)
{

   set_adc_channel(0);
   delay_us(1000);
   result1=0;
   for(i=1;i<=8;i++)
   result1+= read_adc();
   result1/=8;                           /8samples of the adc and dev by8

 
   
   result1=(result1*1000);
   result1=(result1/64)           
//дотук работи като показва резултат при 5в-15000mG и при маса 00000mG

   result1=(result1-8000);      //problemmmmmm
   accx=result1;

      printf(lcd_putc  ,"\fAcc.X: %03.0f", accx);               
   
      printf(lcd_putc,"mG");
     delay_ms(100);
}
}


проблема идва като се опитам да извадя число (8000за момента)
на4и при 5В на входа ми дава 7000 ок ,ама като го дам на маса изкарва -256 :cry:

помагайте плс

п.с другият проблем че това закъснение на последният ред ако го дам 300мс и следва черен дисплей :(


Съб Юли 08, 2006 2:34 pm
Профил ICQ
Ранг: Форумен бог
Ранг: Форумен бог
Аватар

Регистриран на: Чет Окт 07, 2004 1:22 pm
Мнения: 1949
Местоположение: София
Мнение 
Първото важно нещо когато работиш с такива числа - гледай при аритметиката числата да са от еднакъв тип!!
Пример:

В ADC имаш числото 300 (0x12C), конфигурирал си го като 10 битов ADC. Имаш някаква променлива int32 result. Двете числа са от различен тип и следното има много голяма вероятност (в CCS) да не проработи, както очакваш:
Код:
result = read_adc()*512; // Би трябвало резултата да е 153'600

Обаче резултата ти в действителност е 22'530. Обяснението е просто, ADC в случая ти е 16 битово число (понеже 10 битово няма)...компилатора умножава 16 битовото число ADC по 512, резултата от тази операция се записва във temporary регистър на CCS, който също е 16 бита, затова резултата ти остава 16 битово число, което после се записва в result.
За да имаш гарантиран верен резултат (щото в някой случаи може и да работи горния код, ама не се надявай), преди операцията умножение, дефинираш ADC като 32 битово число, и тогава умножаваш по каквото искаш:
Код:
result = (int32)read_adc()*512;

В случая CCS (а и не само той) ще приема ADC като 32-битово число и резултатите от аритметиката с него ще се записват във временен регистър с дължина 32 бита.
Опитай :)


Съб Юли 08, 2006 4:30 pm
Профил
Ранг: Минаващ
Ранг: Минаващ

Регистриран на: Пет Юни 23, 2006 6:54 pm
Мнения: 15
Мнение :)
predator
10x за съветите , взе че тръгна след като сложих всички променливи да са инт 32
пък от ccs форума ми показаха правилният формат за отрицателни числа и запетая %04.3w e това което ми трябваше. пак мерси на всички за помощта ,продължавам да усъвършенствам макетчето :)


Съб Юли 08, 2006 7:29 pm
Профил ICQ
Ранг: Форумен бог
Ранг: Форумен бог

Регистриран на: Нед Сеп 26, 2004 9:21 pm
Мнения: 30684
Местоположение: София
Мнение 
Не знам тая по-проста формулка как си я намерил, те формулките се извеждат от това дето ти написах с оптимизация на операциите стигаш до една формула само с интове за предпочитане. При 5 V трябва да ти показва 8012 ако данните които си дал по горе са верни.
(ADC*Vref/1024-2.5)/0.000312 ако Vref ти е 5 V то
(ADC*5/1024-2.5)/0.000312 = ADC*5/0.319488-8012.82051
ADC*15.65004-8012.82051 това вече зависи от точноста която ти трябва може да се умножи по различни числа
(ADC*156-80128)/10 .... но по дoбре умножвай по тепен на две примерно
(ADC*250-128205)/16 което ще стане
result=((signed int32)adc*250-128205)/16;
тук има еди недостатък, тъй като работиш с signed деленет не е просто >>4 както може да стане с unsigned. Не е много по сложно, но не съм гледал как го прави CCS.


p.s. във формулата от предния ми пост вместо делено съм писал умножено, което е глупост естествено


Съб Юли 08, 2006 8:32 pm
Профил
Ранг: Минаващ
Ранг: Минаващ

Регистриран на: Пет Юни 23, 2006 6:54 pm
Мнения: 15
Мнение :)
направих всички променливи и резултата от ацп int32 за да си нямам проблеми :D
да , нещо подобно е

има малко объркване от факта че датчика не дава от 0-5В а 0.94 до 4.06В

т.е със закръглените сметки при 4.06 АДЦ=831,488 абе грубо 831 което по формулата

831/64 -8 = 4.992 Г
всъщност я направих в mG -адц_число*1000/64-8000
и това 8000 преди малко го коригирах (за двата канала е разли4но понеже датчика е в кутиика и не е много хоризонтален но го въртя по оста зех 10ина стойности и ги усредних

самата корекция явно може да стане и софтуеърно че и доста по точно но това ми е първа реализация на платка и първо програмиране пък и е за лична употреба така че за момента точност дори 1/10 е добре :) (пуснах му и едно пиезо да цвърчи като се премине праг от 1200мГ :) и стана интересно ,ще го пробвам в колата тези дни
--------------------------
обаче имам друг въпрос
Искам да го направя да мери и мощност
P=F.V=m.a.a.t (a-uskorenie m -masa;t-wreme)

вече имаме ускорение; , при твърдо зададена маса на автомобила да кажем 1300кг (което по натам може да се направи да се въвежда чрез бутони)остава да се измери времето

идеята ми е за време 1 или 0.5секунди да се намери Gсредно -това ясно
обаче незнам как да отмервам интервали 0.5 или 1 секунда като за всеки от тях си се изчислява "а" съответно и "Р" ,което по необходимия коефицент (1.36 май) дава моментна мощност в конски сили 8)

ако някой може да помогне да каже как да отмеря интервал време понеже тепърва се уча на С а и тепърва разучавам ПИК.
пс.кварца ми е на 10Мхц (ако може някакъ цикъл с броене на цикли без таймери че още не ми е узряла кратуната за тях :lol: )


Поздрави


Нед Юли 09, 2006 10:46 am
Профил ICQ
Ранг: Почетен член
Ранг: Почетен член
Аватар

Регистриран на: Чет Ное 25, 2004 3:42 pm
Мнения: 913
Мнение 
Аз съм си мечтал за такава джаджа така и не се организирах да я направя.
Но съм мислил по-прблема.
Не знам датчика който ползваш дали е с една или три оси.
Проблема които ще възникне е че при потегляне колата се накланя назад и към измерваното ускорение ще се добави част от земното.
Ако си с три оси това ще го коригираш софтуерно.
Но ако си с една докато не е късно променяй хардуера.


Нед Юли 09, 2006 11:00 am
Профил
Ранг: Минаващ
Ранг: Минаващ

Регистриран на: Пет Юни 23, 2006 6:54 pm
Мнения: 15
Мнение mda
и аз стихнах до този извод , моят е с две и даже ми дойде идеята да не го поставям в хоризонтална равнина ами едната да по оста на колата другата отвесно(ама пък като праиш метла нямаш инфо за Г-то)за да хвана дигането на муцуната на звера (а пък на завоите ше има малко грешка ама ...)(за момента ще го монтирам някаде централно в купето че да е малък ъгълът пък натам ще видим)иначе наистина наи добре с 3оси и с няква математика става екстра

ама хаиде казвайте как да меря времето че по интерсно ще е да смята хорс пауър отколкото Г 8)


Нед Юли 09, 2006 11:21 am
Профил ICQ
Ранг: Форумен бог
Ранг: Форумен бог

Регистриран на: Нед Сеп 26, 2004 9:21 pm
Мнения: 30684
Местоположение: София
Мнение 
Ами с таймерите, аз бих пуснал един таймер да дава прекъсвания на всеки 10 мс, на всяко прекъване мериш датчика. Щом ти трябва за секунда на 100 измервания усредняваш, а за индикацията може да вадиш междинен резултат на всеки 10. Гледам ползваш CCS там във уизърда напрво може да си настроиш таймера на колко да ти дава преъсване, ако търсиш точност не те съветвам да позлваш директно това, ще тряба да го презареждаш ръчно като преди това го четеш, иам писано по темата .....


Нед Юли 09, 2006 11:30 am
Профил
Ранг: Минаващ
Ранг: Минаващ

Регистриран на: Пет Юни 23, 2006 6:54 pm
Мнения: 15
Мнение .
ахам ,ако някои има някакъв примерен код за таймер понеже както казах едва започвам със С и о6те съм на прости надписи и сметки и нямам идея като синтаксис как трябва да укажа на всяко прекъсване да се взима резултат или на всеки 100 прекъсвания примерно.... :?


Нед Юли 09, 2006 11:35 am
Профил ICQ
Ранг: Почетен член
Ранг: Почетен член
Аватар

Регистриран на: Чет Ное 25, 2004 3:42 pm
Мнения: 913
Мнение 
Няма ли команда от типа DELAYMS Length
Ако не което ме съмнява.
Организирай си сам един цикъл на изчакване. Като нещещ таймер. Какво му се чудиш виж за колко се изпълнява една инструкция и вътриш колкото е необходимо. После мериш.


Нед Юли 09, 2006 12:29 pm
Профил
Ранг: Форумен бог
Ранг: Форумен бог

Регистриран на: Нед Сеп 26, 2004 9:21 pm
Мнения: 30684
Местоположение: София
Мнение 
на всяко ..... таймерите се сетват с setup_timer() виж хелпа, примерно :
setup_timer_0(RTCC_DIV_2); това ти сетва таймер 0 да работи в режим на броя1 с вътрешен клок с прескалер 2. Т.е. ако честотата ти е 4 Mhz на кварца, вътрешната ти е 1 Mhz, т.е. делено на 2 тймера ще се тактува с 500 khz, или ще се инкрементва на всеки 2 us. Таймера е 8 битов, т.е. препълване ще имаш на 512 us. В този случай за 10 ms имаш 10/256~0.039 мс, т.е. трябва да делиш на 39, такъв делител няма, избираш по големия, 64 и получаваш. 1 Mhz/64 = 15.625 Khz = 0.064 ms Сега смяташ колко ти трябва за да получиш 10 мс, 10/0.064 = 156,25 или 156. Т.е. трябва да сложиш таймера на да дели на 64 и да заредиш в него 100, за да имаш 156 такта до препълване.
setup_timer_0(RTCC_DIV_64);
set_timer0(100);

след това във прекъсването също трябва да го зареждш със тази стойност.
#INT_RTCC
RTC_ISR()
{

SET_TIMER0(100);
start adc conversion
}

вече в зависимост на колко делиш и колко ти се губи в прекъсване може да се наложи да коригираш стойността която зареждаш, тъй като таймера може да се е инкрементнал вече един или няколко пъти. Просто го четеш и вадиш това кеото си прочел от това което искаш да заредиш, редно е и да си предивдиш времето за изчитане на таймера и калкулиране на това кето ще зареждаш както и времето за зареждане.
В случая ще има прекъсване на всеки 156*0.064 мс или на вски 9.984 мс. За по голяма точност трябва да си избереш подходящ кварц.


Нед Юли 09, 2006 12:45 pm
Профил
Покажи мненията от миналия:  Сортирай по  
Отговори на тема   [ 13 мнения ] 

Кой е на линия

Потребители разглеждащи този форум: 0 регистрирани и 9 госта


Вие не можете да пускате нови теми
Вие не можете да отговаряте на теми
Вие не можете да променяте собственото си мнение
Вие не можете да изтривате собствените си мнения
Вие не можете да прикачвате файл

Търсене:
Иди на:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group.
Designed by ST Software for PTF.
Хостинг и Домейни