Перейти к содержанию

Нелинейная Характеристика Аналогового Датчика


Рекомендуемые сообщения

Думаю это финальная программа. Рабочая. Все подисал как дилетант для дилетантов.

Специально не подписывал переменные, потому что когда я раньше пытался читать программы я читал что за переменная и для чего, читал далее и пытался сопоставить для чего эта переменная и не понимал. Очень путало. Ведь по сути переменная когда объявляется переменная она по сути в этот момент никто и ничто =) она будет кем то только после того как будут какие то действия с ней. Но еще раз говорю это чисто для понимания дилетантам вроде меня =)

Тут писали что будет погрешность. Так вот назовите температуру от 0 до 100 которая будет иметь максимальную погрешность по вашим расчетам а я проверю.

/*
* File: newmain.c
* Author: Vlad
*
* Created on 16 ???????? 2015 ?., 0:37
'11-a RB5
'13-b RB7
'7-c RB1
'9-d RB3
'6-e RB0
'10-f RB4
'12-g RB6
'8-dp RB2
' RA3 dig1
' RA2 dig2
' RA7 dig3
*
* $82 - E, $08 -R
*
*/
#pragma config FOSC = INTOSCIO // Oscillator Selection bits (INTRC oscillator; port I/O function on both RA6/OSC2/CLKO pin and RA7/OSC1/CLKI pin)
#pragma config WDTE = OFF	 // Watchdog Timer Enable bit (WDT enabled)
#pragma config PWRTE = ON	 // Power-up Timer Enable bit (PWRT enabled)
#pragma config MCLRE = OFF	 // RA5/MCLR/VPP Pin Function Select bit (RA5/MCLR/VPP pin function is digital I/O, MCLR internally tied to VDD)
#pragma config BOREN = ON	 // Brown-out Reset Enable bit (BOR enabled)
#pragma config LVP = OFF	 // Low-Voltage Programming Enable bit (RB3/PGM pin has digital I/O function, HV on MCLR must be used for programming)
#pragma config CPD = OFF	 // Data EE Memory Code Protection bit (Code protection off)
#pragma config WRT = OFF	 // Flash Program Memory Write Enable bits (Write protection off)
#pragma config CCPMX = RB2	 // CCP1 Pin Selection bit (CCP1 function on RB2)
#pragma config CP = OFF		 // Flash Program Memory Code Protection bit (Code protection off)
#include <xc.h>
#include <pic.h>
#include <pic16f819.h>
#include <stdlib.h>

#define dig1 RA3 //индикатор 1
#define dig2 RA2 //индикатор 2
#define dig3 RA7 //индикатор 3
//#define tochka RB2
#define warning RA1 //отдельный светодиод

#define LED PORTB
const unsigned char digits [14] = {0x44,0x7D,0x16,0x15,0x2D,0x85,0x84,0x5D,0x04,0x05,0xFF,0x86,0x0C, 0xBF}; //0,1,2,3,4,5,6,7,8,9,пусто, E,R, - // это коды которые сообщают какие светодиоды поджечь в индикаторе чтобы отобразить ту или иную цифру или символ. Код зависит от того какая нога к какому выводу МК подрублена. в инете есть калькуляторы.
		 unsigned int i			 ; //
volatile	 unsigned char a,b			 ;//volatile это спецификатор говорит компилятору, что это переменная, чтобы он ее не оптимизировал, Отдельная плюшка)
volatile	 unsigned char LEDS[3]		 ; //


//***********************************************************************
//* ИНИЦИАЛИЗАЦИЯ МК
//***********************************************************************
void init(void)
{
INTCON =0x00; // запрет всех прерываний
OSCCON = 0b01100100; //с 4 по 6 бит значение 110 означает 4mhz
// ниже настройка портов
PORTA = 0; //обнуляем порты а
PORTB = 0;
TRISA = 0b01110001; //порты RA2, RA3, RA7, RA1 на выход а остальные на вход
TRISB = 0b00000000; // все порты RB на выход
PORTA = 0; //обнуляем порты а
PORTB = 0;
warning=1; //вырубаем варнинг светодиод на всякий случай.
// ниже настройка АЦП
ADCON0=0b01000001; //тактирование АЦП Fosc/8, выбран канал AN0, модуль АЦП включен
ADCON1=0b10001110; //правое выравнивание, включен аналоговый вход RA0/AN0, остальные входы цифровые
// ниже настройка таймера TMR0
TMR0 = 0; //сбрасываем таймер в 0
OPTION_REG = 0b00000011; // настройки таймера 1:16 и установка Set timer TMR0 даташит page 54:
// ниже разрешение прерываний
TMR0IE = 1; //разрешение прерывания по таймеру0
GIE = 1; // глобальное разрешение прерываний
};
int adcsf (int s); //прототип функции сглаживания
adcsf (s){ //сама функция сглаживания показаний, чтобы температура не дергалась в промежуточных местах. При вызове функции она обработается и выдаст значение s
int adc;
unsigned int tmp;
static unsigned int old_adc; //static означает что при выходе из этой функции значение old_adc не будет потеряно
ADCON0bits.GO = 1; //запускаем ацп
while (ADCON0bits.GO){NOP();}; // если ацп работает то ниче не делаем.
//ниже если ацп закончило свое действие и не работает то выполняем код ниже
tmp = (ADRESH<<8)+ADRESL; //помещаем значение ацп в переменную tmp чтобы могли с ним работать ниже
if (tmp>=4 && tmp<=1010){ //если значение АЦП от 4 до 1010 то выполняем тело а именно применяем формулу сглаживания
adc = ((old_adc<<1)+old_adc+tmp)>>2; // сдвиг влево соответствует умножению на 2, а сдвиг вправо — делению на 2. Формула сглаживания. Изначально old_adc равно нулю
old_adc=adc; // присваиваем переменной old_adc значение adc а оно равно результату формулы выше
s=adc; // присваиваем переменной s значение переменной adc
}
else { //если ацп не попадает в диапазон от 4 до 1010 то выполняем тело ниже
s=tmp; // присваиваем переменной s значение переменной tmp а оно равно значению АЦП
}
}

void interrupt Timer (void)
{ //прерывание по таймеру для динамической индикации
if(TMR0IF) // таймер считает до такого числа которое мы указали в настройках таймера " OPTION_REG = 0b00000011; // настройки таймера 1:16 и установка Set timer TMR0 даташит page 54" и когда он досчитает он поднимает флаг, мол я досчитал! флаг TMR0IF если он равен 1 значит он поднят и выполняется тело ниже
 {
	 TMR0IF=0; //сбрасывается этот же флаг чтобы он начал считать заново.
	 dig1=0; NOP(); dig2=0;NOP(); dig3=0; LED=(digits [10]); // гасим все разряды
	 b++; //увеличиваем b на 1. изначально она равна нулю.
	 if (b>130){b=0;} //если b уже равна больше 130 то обнуляем её. Это как бы второй счетчик, параллельный основному.
	 a++; //тоже что и b но счетчик для индикации
	 switch(a) //выбор вариантов в зависимости от значения а. В первый раз а будет равно 1 и поэтому будет работать case 1
 {	 // Динамическая индикация.
		 case 1: LED=(LEDS[2]); dig1=0; NOP(); dig2=0; NOP(); dig3=1; break; // сначала отправляем цифру LEDS[2] а потом поджигаем первый разряд dig3=1 чтобы увидеть эту цифру
		 case 2: LED=(LEDS[1]); dig1=0; NOP(); dig3=0; NOP(); dig2=1; break; // второй разряд
		 case 3: LED=(LEDS[0]); dig2=0; NOP(); dig3=0; NOP(); dig1=1; a=0; break; // третий разряд и вконце обнуляем a и счетчик теперь опять будет считать с 0
 }
}
}
int LinearAPPROX(int tm) //функция конвертирования АЦП в температуру нелинейной характеристики резистивного датчика. кусочно-линейная аппроксимация. результат будет значение tm
{
 int adc, s;
 adc = adcsf (s); //помещаем значение s в переменную adcsf которое получилось в функции сглаживания adcsf

 if(adc>=10 && adc<175){ //если температура выше 100 градусов (меньше значения ацп 175 ) то выдает значение АЦП в переменную tm для дальнейшей калибровки
tm=adc;
}
 if(adc>=174 && adc<=675){
tm=((-130L*adc+125344)/1024); //tm равно уравнению от 36.6 до 100, линейный график с точками (174, 100) и (675, 36.6)
}
 if(adc>=676&& adc<=836){
tm=((-132L*adc+126644)/1024); //уравнение от 15.8 до 36.6
}
 if(adc>=837 && adc<=898){
tm=((-211L*adc+192704)/1024); //уравнение от 15.8 до 3
}
 if (adc>898 && adc<1000) {
	 tm=((-291L*adc+264222)/1024); //уравнение от 3 до -15 и далее но меньше -15 уже не точно.
}
 if(adc<4 ){ //Если значение adc меньше 4 (тоесть замыкание на землю и 0 вольт)
tm=1022; //то присваиваем переменной tm вымышленное значение температуры в 1022 градуса
 }
 if(adc>1010){ //тоже самое только при отсутствии вообще датчика
tm=1023; //и присваиваем переменной tm вымышленное значение температуры в 1023 градуса
 }
}
void convert (void)//функция которая переводит значения температуры в графические показания на 3 разрядном семисегментном индикаторе
{
unsigned int d1_1; //
int tm;
unsigned char tempLEDS[3]		 ; // масив в который будем заносить значения из другого массива (не числа)

tm = LinearAPPROX(tm); //вызываем функцию LinearAPPROX и присваиваем значение аргумента tm переменной с таким же именем просто чтобы не запутаться

if ( tm==1023) //если значение температуры равно 1023 то выполняем тело
 { //ниже тело, отправляется на иникатор "ERR"
 tempLEDS[0]= digits [12]; //R //А точнее в массив tempLEDS в ячейку с индексом 0 помещается значение ячейки массива digits с индексом 12
 tempLEDS[1]= digits [12]; //R
 tempLEDS[2]= digits [11]; //E

 warning=0; //и врубается варнинг светодиод.
}

if ( tm==1022) //если значение температуры равно 1022 то выполняем тело
 { //ниже тело, отправляется на иникатор "000"
 tempLEDS[0]= digits [0]; //0
 tempLEDS[1]= digits [0]; //0
 tempLEDS[2]= digits [0]; //0
 warning=0;	 //и врубается варнинг светодиод.
}
else // если tm не 1023 и не 1022 то выполняется тело ниже
 {

 NOP(); // просто микро пауза

 if(tm<0){ //если tm меньше 0 (температура ниже нуля) к примеру -30
	 d1_1=abs(tm%100); //присваиваем переменной d1_1 значение по модулю остаток от деления на 100. Тоесть -30 делим на 100 получаем по модулю 0.3 и остаток это 3.
	 tempLEDS[2]= digits [13]; //в массив tempLEDS в ячейку с индексом 2 (это первый индикатор) помещается значение ячейки массива digits с индексом 13 это просто черточка минус

	 tempLEDS[1]=digits [d1_1/10]; //во второй индикатор помещаем результат деления d1_1 на 10, тоесть как посчитали выше 0.3 и делим на 10 получаем 3			
	 tempLEDS[0]=digits [d1_1%10]; //в третий индикатор помещаем остаток от деления d1_1 на 10, тоесть 0.3 делим на 10 получаем 3.0 а остаток 0
 warning=0; //и врубается варнинг
	 }


 if(tm>=0 && tm<10){ //если tm больше 0 но меньше 10 то выполняем тело
	 tempLEDS[2]=digits [10]; //посылаем пустой знак
	 NOP();
	 tempLEDS[1]=digits [10]; //посылаем пустой знак
	 NOP();
	 tempLEDS[0]=digits [tm]; //посылаем знак равный tm
 }
 if (tm >= 10 && tm <= 99){
	 tempLEDS[2]=digits [10]; // если значение от 10 до 99 то на 1 индикатор подаем цифру пусто.
	 NOP();
	 d1_1=tm%100;
	 tempLEDS[1]=digits [d1_1/10];				 // Получаем разряд
	 tempLEDS[0]=digits [d1_1%10];			 // Получаем разряд
	 if (tm < 40 ){warning=0;NOP();} // врубаю варнинг если температура ниже 40
	 if (tm > 39 ){warning=1;NOP();} // вырубаю варнинг если температура выше 39
 }
 if (tm >=100 && tm < 999 ){// аналогично но для температур от 100 до 999
	 d1_1=tm%100;
	 tempLEDS[2]=digits [tm/100];// Получаем разряд
	 tempLEDS[1]=digits [d1_1/10]; // Получаем разряд
	 tempLEDS[0]=digits [d1_1%10]; // Получаем разряд
	 if (tm > 110 ){ // врубаю морганием варнингом если температура выше 110
		 if (b>60){ //если счетчик b насчитал больше 60 то выполняем тело ниже
			 warning=0; //а именно врубаем светодиод
				 }
	 if (b>120){ //но если он уже досчитал больше 120 то
		 warning=1; //вырубаем светодиод
		 b=0; //и сбрасываем счетчик b
				 }
		 }
	 if (tm < 110 ){warning=1;NOP();} // вырубаю варнинг если температура ниже 110
 }

 }
GIE = 0;// глобальный запрет прерываний чтобы три переменных ниже записались и запись не прервалась каким нить прерыванием случайно.
// ниже по сути идет описания массива LEDS чему равны его ячейки
 LEDS[0]= tempLEDS[2]; // значению массива LEDS с индексом 0 присваиваем значение массива tempLEDS с индексом 2, если почитать выше то будет видно что мы присваиваем посчитанные значения разрядов.
 LEDS[1]= tempLEDS[1];
 LEDS[2]= tempLEDS[0];
GIE = 1;// врубаем прерывания заново.	

}
//***********************************************************************
//* ОСНОВНАЯ ПРОГРАММА
//***********************************************************************
void main (void)
{
 init(); //вызывается функция init
 for(i=255;i>0;i--); //небольшая пауза
 //******** ГЛАВНЫЙ ЦИКЛ *****************
 while (1) //бесконечный цикл
	 {
	 convert (); //в котором вызывается функция convert, ищим её выше и смотрим что в ней происходит и какие в ней функции вызываются.
	 };
}

Ссылка на комментарий
Поделиться на другие сайты

Реклама: ООО ТД Промэлектроника, ИНН: 6659197470, Тел: 8 (800) 1000-321

  • Ответов 80
  • Создана
  • Последний ответ

Топ авторов темы

Не смогу погрешность проверить. Есть вопросы.

1. Не знаю, какая схема на входе АЦП.

2. Не знаю, какой код выдает АЦП при напряжениях 0,500в и 4,500в (или любых других напряжениях, но близких к указанным). Фактически нужна калибровка.

3. Не знаю, какой номинал Rд, если схема похожа на пост #65.

4. Не знаю, на какой диапазон температур проектируется термометр от -40°С до 200°С хватит?

Только после ответов на эти вопросы будем погрешности считать. Сейчас мне просто нечего сказать. Я же таблицы по отрывочным и неточным сведениям строил. Мог и наврать.

Ссылка на комментарий
Поделиться на другие сайты

20% скидка на весь каталог электронных компонентов в ТМ Электроникс!

Акция "Лето ближе - цены ниже", успей сделать выгодные покупки!

Плюс весь апрель действует скидка 10% по промокоду APREL24 + 15% кэшбэк и бесплатная доставка!

Перейти на страницу акции

Реклама: ООО ТМ ЭЛЕКТРОНИКС, ИНН: 7806548420, info@tmelectronics.ru, +7(812)4094849

Вот я к примеру хочу построить термометр на датчике с даташитом. Вот картинка из даташита. Как мне по этой картинке понять какая характеристика у датчика? Что вбивать в программу?

7BW7NBpuw1E.jpg

Вообще это датчик давления. но в нем есть термистор.

датчик давления.pdf

Ссылка на комментарий
Поделиться на другие сайты

Выбираем схему BMS для корректной работы литий-железофосфатных (LiFePO4) аккумуляторов

 Обязательным условием долгой и стабильной работы Li-FePO4-аккумуляторов, в том числе и производства EVE Energy, является применение специализированных BMS-микросхем. Литий-железофосфатные АКБ отличаются такими характеристиками, как высокая многократность циклов заряда-разряда, безопасность, возможность быстрой зарядки, устойчивость к буферному режиму работы и приемлемая стоимость. Но для этих АКБ, также как и для других, очень важен контроль процесса заряда и разряда, а специализированных микросхем для этого вида аккумуляторов не так много. Инженеры КОМПЭЛ подготовили список имеющихся микросхем и возможных решений от разных производителей. Подробнее>>

Реклама: АО КОМПЭЛ, ИНН: 7713005406, ОГРН: 1027700032161

Что значит "как понять какая характеристика у датчика" ? Вон же она, на правой картинке нарисована. Что там может быть непонятного ?

Что вбивать в программу?
Зависимость значений АЦП от температуры.

Странно, столько советов тут было, а Вы до сих пор такие вопросы задаёте.

Вам, по сути, вообще не нужен этот график. Вам надо узнать значения АЦП на определённых точках температуры, а не значения сопротивлений ! И только потом уже строить свой собственный график зависимости "железа" от температуры !

Ссылка на комментарий
Поделиться на другие сайты

Внимательно посмотри на график. Цифры 102, 103, 104 и 105 обозначают сопротивления 100, 1000, 10000 и 100000 ом, соответственно. Отношение максимального значения к минимальному составляет 1000 раз. Это только кажется, что график почти линейный. В нормальной системе координат его даже нарисовать нельзя. Попытка вести расчет по данным с этого графика обречена на провал. Слишком большая погрешность.

Вот почему для каждого датчика нужна экспериментальная проверка.

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

Сделай нормальную таблицу зависимости сопротивления датчика от температуры. Я ее в очередной раз сам в программу забью. Заодно и посмотришь, как это делается. А то мы тут до конца года будем модераторов троллить.

Ссылка на комментарий
Поделиться на другие сайты

  • 4 недели спустя...

Вот к примеру есть даташит на датчик температуры:

post-147349-0-28771400-1445557711_thumb.jpg

Что такое Expansion of Tolerance и зачем он нужен? к примеру при 125 градусах коэффициент равен 1.5 что это?

Ссылка на комментарий
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы публикуете как гость. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.
Примечание: Ваш пост будет проверен модератором, прежде чем станет видимым.

Гость
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Ответить в этой теме...

×   Вставлено с форматированием.   Восстановить форматирование

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

Загрузка...
  • Последние посетители   0 пользователей онлайн

    • Ни одного зарегистрированного пользователя не просматривает данную страницу

×
×
  • Создать...