Микроконтроллеры, АЦП, память и т.д Темы касающиеся микроконтроллеров разных производителей, памяти, АЦП/ЦАП, периферийных модулей... |
12.03.2008, 21:11
|
#1
|
Вид на жительство
Регистрация: 18.06.2006
Сообщений: 434
Сказал спасибо: 0
Сказали Спасибо 12 раз(а) в 12 сообщении(ях)
|
ADC преобразования.
Не получается мерить напряжение.
Обрабатываю и в результате получается какой то каламбур.
Схема подключения через обычный делитель, при изменении измеряемого напряжения на 200mV , на входе АЦП напряжение меняется 40mV.
НА выходе получается какой то каламбур.
Вот таблица снятых параметров.
U-измеряемое | t1, t2
10V | 0D, 03
10,2V | 0E, 02
10,4V | 10, 02
10,6V | 14, 03
от 10,8V до 11,6V | 1D, 02
от 11,7V до 12,2V | 25, 01
12,3V | 29, 01
от 12,66V до 13,4V| 2D, 02
13,43V | 2E, 01
Первое значение это 8 старших байт, второе 2 младших.
Почему получается что в некоторых интервалах получаются одни и теже данные. Напряжение регулюрую ШИМом по 10mV.
Вот код обработчика АЦП, контроллер PIC16F877A
Код:
|
...
adc_res = ADConverts(200);
t1 = (adc_res ›› 2);
t2 = (adc_res & 0x0003);
SeyAT_ch(t1);
SeyAT_ch(t2);
//функция SeyAT_ch() просто передает значение в регистр TXREG. чтоб видеть их в терменале.
...
unsigned int ADConverts(char index)
{
unsigned int itemp=0;
unsigned char ctemp=0;
char i=0;
for (;i‹index;i++)
{
ADGO=1;//запускаем преобразование
while (!f_adc) continue;//ждем завершения приобразования
itemp = itemp + ADRESH;
ctemp = ctemp + (ADRESL ›› 6);
}
return ((itemp ‹‹ 2) / index) + (ctemp / index);
} |
|
|
|
|
12.03.2008, 22:44
|
#2
|
Временная регистрация
Регистрация: 11.12.2007
Сообщений: 79
Сказал спасибо: 0
Сказали Спасибо 1 раз в 1 сообщении
|
Я не понимаю смысл этих телодвижений.
Код:
|
itemp = itemp + ADRESH;
ctemp = ctemp + (ADRESL ›› 6);
}
return ((itemp ‹‹ 2) / index) + (ctemp / index); |
Разве не лучше где-то вверху объявить что-то типа
Код:
|
typedef union
{
struct {
unsigned char lo;
unsigned char hi;
}st;
unsigned int all;
}tun;
tun t; |
И обращаться, когда нужно, то к старшему байту, то к младшему, а то и к инт. В данном случае
Код:
|
t.st.lo=ADRESL;
t.st.hi=ADRESH;
itemp+=t.all; |
И учитывая, что значение инт при захвате числа может быть 1023, ограничить сумму 64. Потом результат (инт) сдвигаем вправо - и все.
Да !!! И бойтесь длинных выражений - компилятор их не любит. Иногда лучше лишнюю переменную поставить, чтобы разбить строчку на 2 - 3 части.
|
|
|
|
12.03.2008, 23:27
|
#3
|
Вид на жительство
Регистрация: 18.06.2006
Сообщений: 434
Сказал спасибо: 0
Сказали Спасибо 12 раз(а) в 12 сообщении(ях)
|
Мне нужно не плюсовать данные, функция делае измерения index раз, они сумируются делятся на index раз находим среднее арифметическое, для более точного измерения. Потом выводит результат.
|
|
|
|
13.03.2008, 00:20
|
#4
|
Временная регистрация
Регистрация: 11.12.2007
Сообщений: 79
Сказал спасибо: 0
Сказали Спасибо 1 раз в 1 сообщении
|
Код:
|
unsigned int adc_sum(void)
{
unsigned int z=0;
for(i=0;i‹64;i++)
{
GODONE=1;
do{
}while (GODONE==1);
t.st.hi=ADRESH;
t.st.lo=ADRESL;
z+=t.all; // сложили 64 раза
}
z››=6;// поделили на 64
return z;
} |
И в программе
Код:
|
t.all=adc_sum();
SeyAT_ch(t.st.hi);
SeyAT_ch(t.st.lo); |
|
|
|
|
13.03.2008, 12:55
|
#5
|
Вид на жительство
Регистрация: 18.06.2006
Сообщений: 434
Сказал спасибо: 0
Сказали Спасибо 12 раз(а) в 12 сообщении(ях)
|
Это вариант то же не работает, получается какаято ерунда.
Вот что я получаю
U-ацп | t1, t2
1,93V | 02, C0
1,97V | 02, C0
2,01V | 02, 60
2,04V | 00, 80
2,12V | 00, 80
2,16V | 02, 40
2,35V | 00, 00
Код:
|
#include ‹pic.h›
void SeyAT_ch(const char AT);//отправка символа
unsigned int adc_sum(void);
typedef union
{
struct {
unsigned char lo;
unsigned char hi;
}st;
unsigned int all;
}tun;
tun t;
char i;
bit f_adc;//АЦП преобразование завершено
void interrupt other(void)
{
if (RCIF==1)
{
i=RCREG;
}
if (ADIF==1)
{
f_adc=1;
ADIF=0;
}
}
int main()
{
unsigned int adc_res=0;
unsigned char t1=0;
unsigned char t2=0;
__CONFIG(HS & PWRTDIS & WDTDIS & BORDIS & LVPDIS/* & PROTECT*/);
STATUS=0x00;
RCSTA=0b10010000;//настройка приемника uart
TXSTA=0b00100100;//настройка передатчика uart
SPBRG=10;// скорость uart 57600 baund
INTCON=0b11000000;//разрешения прирываний
T2CON=0X00;
RCIE=1;//прерывания от приемника uart
ADCON0=0b00000001;//включаем АЦП
ADCON1=0b00001110;//устанвливаем выходи
ADIE=1;//прерывание для АЦП
TRISA=0XFF;//настройка порта A
TRISB=0XFF;//настройка порта В
TRISC=0b10111111;//настройка порта C
TRISD=0XFF;//настройка порта D
TRISE=0XFF;//настройка порта E
ADIF=0;//флаг прерывания от АЦП
for (;;)
{
if (!RB6)
{
t.all=adc_sum();
SeyAT_ch(t.st.hi);
SeyAT_ch(t.st.lo);
}
while (!RB6) continue;
}
}
void SeyAT_ch(char AT)
{
while(TXIF!=1) continue;
TXREG=AT;
}
unsigned int adc_sum(void)
{
unsigned int z=0;
for(i=0;i‹64;i++)
{
ADGO=1;//запускаем преобразование
while (!f_adc) continue;//ждем завершения приобразования
t.st.hi=ADRESH;
t.st.lo=ADRESL;
z+=t.all; // сложили 64 раза
}
z››=6;// поделили на 64
return z;
} |
|
|
|
|
13.03.2008, 14:16
|
#6
|
Почётный гражданин KAZUS.RU
Регистрация: 06.02.2007
Сообщений: 1,340
Сказал спасибо: 3
Сказали Спасибо 106 раз(а) в 66 сообщении(ях)
|
Глубоко не лез, но вижу, что программа написана под выравнивание старшего байта вправо, а у Вас стоит выравнивание влево.
ADCON1=0b00001110;//устанвливаем выходи
добавьте старший бит в 1 - и на будущее старайтесь записывать биты, которые имеют значение - иначе легко ошибиться и ошибка не так уж сильно видна.
Дальше -нагружайте больше комп вычислениями, что-то типа
Код:
|
#define XTAL 20000000
#define VBOD 57600
#define SBRG_ ((XTAL /VBOD) -16)/16
BRGH =1;
SPBRG=SBRG_;// скорость uart 57600 baund |
|
|
|
|
13.03.2008, 15:32
|
#7
|
Вид на жительство
Регистрация: 18.06.2006
Сообщений: 434
Сказал спасибо: 0
Сказали Спасибо 12 раз(а) в 12 сообщении(ях)
|
В моем варианте все верно было, я не знаю зачем советуют так усложнять, на самом деле мне не нужно ни чего разбивать на регистры, так что ни каких структур не нужно, мне нужно 10бит значение в типе int, а разбиваю я просто чтоб на терминал вывести.
Вот мой вариант, все должно работать, но на самом деле мереет до 11В а потом начинает висеть на одни и те же значения, а потом сразу через промежуток выводит как я и описывал в первом посте.
Вот мой вариант давайте от него опираться.
Код:
|
...
adc_res = ADConverts(80);
t1 = (adc_res ›› 2);
t2 = (adc_res & 0x0003);
SeyAT_ch(t1);
SeyAT_ch(t2);
//функция SeyAT_ch() просто передает значение в регистр TXREG. чтоб видеть их в терменале.
...
unsigned int ADConverts(char index)
{
unsigned int itemp=0;
unsigned char ctemp=0;
char i=0;
for (;i ‹ index;i++)
{
ADGO=1;//запускаем преобразование
while (!f_adc) continue;//ждем завершения приобразования
itemp += ADRESH / 2;
ctemp += ADRESL ›› 6;
f_adc=0;
}
return (((itemp ‹‹ 2) / (index-1))*2) + (ctemp / (index-1));
} |
Не поленился и еще раз зделал измерения по этому коду:
U-измеряемое | U-после делителя | t1 | t2
10,00V | 1,91V | 61 | 01
10,20V | 1,95V | 61 | 03
10,40V | 1,99V | 63 | 03
10,60V | 2,02V | 67 | 02
10,80V | 2,06V | 71 | 00 !!!!!!!!!!!!
11,60V | 2,22V | 71 | 00 !!!!!!!!!!!!
11,80V | 2,25V | 79 | 02 !!!!!!!!!!!!
12,30V | 2,34V | 79 | 02 !!!!!!!!!!!!
12,33V | 2,35V | 7D | 02
В чем проблема?
|
|
|
|
13.03.2008, 16:19
|
#8
|
Почётный гражданин KAZUS.RU
Регистрация: 06.02.2007
Сообщений: 1,340
Сказал спасибо: 3
Сказали Спасибо 106 раз(а) в 66 сообщении(ях)
|
Вы читаете, что Вам пишут ??? ПРАВОЕ ВЫРАВНИВАНИЕ !!!
ADCON1=0b 10001ХХХ; - Вы сделали ???
Ваш проект в протеусе прилагаю.
Прикрепленный файл: 2720946.rar
|
|
|
|
13.03.2008, 16:58
|
#9
|
Вид на жительство
Регистрация: 18.06.2006
Сообщений: 434
Сказал спасибо: 0
Сказали Спасибо 12 раз(а) в 12 сообщении(ях)
|
Подождите я может чегото не допонял?
ADFM: 0-левое выравнивание, 6 младших бит ADRESL читаются как 0, то есть то что на изоброажении.
Код:
|
itemp = ADRESH;//itemp = NNNNNNNNXXXXXXXX
ctemp = ADRESL ›› 6;// ctemp = NNNNNNXX
itemp ‹‹ 2;//itemp = 000000XXXXXXXX00
+ ctemp;//itemp = 000000XXXXXXXXXX |
X - полезные биты
Разве не правильно?
p/s По рисунку 10-й в смысле 9-й
-- Прилагается рисунок: --
|
|
|
|
13.03.2008, 17:46
|
#10
|
Почётный гражданин KAZUS.RU
Регистрация: 06.02.2007
Сообщений: 1,340
Сказал спасибо: 3
Сказали Спасибо 106 раз(а) в 66 сообщении(ях)
|
Нет, это я тупой. Не понимал, зачем использовать левое выравнивание и куда-то что-то сдвигать, если есть правое, при котором ничего никуда двигать не нужно.
Что касается Вашего последнего поста, то там пара ошибок
вместо itemp ‹‹ 2;
itemp ‹‹= 2;//
вместо + ctemp;
itemp+= ctemp;//
Ваш вариант в протеусе с левым выравниванием прилагаю
Прикрепленный файл: 8170770.rar
|
|
|
|
Ваши права в разделе
|
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения
HTML код Выкл.
|
|
|
Часовой пояс GMT +4, время: 02:53.
|
|