Еще один термометр на Attiny45 и сдвиговом регистре

Обсуждаем контроллеры компании Atmel.
Ответить
Родился
Аватара пользователя
Сообщения: 8
Зарегистрирован: Пн дек 24, 2012 02:56:24

Сообщение drBOR »

Наводя порядок нашел tiny45 7сегм. индикатор и НС595й сд.регистр
Возникла идея создать на данных элементах термометр в баньку. Весь вкус состоял в том что бы испоьзуя attiny45 с его недостатком ног считать с 18b20 температуру и вывести на 7сегментный индикатор используя только одну ИМС сдвигового регистра. Т.к. елементы были в SOP и SOIC корпусах то конечное устройство должно было получиться миниатюрным и влезть в корпус сгоревшей гал.лампочки под 12В , микросхема датчика температуры размещается на плате или выносным монтажем. Плата изготавливалась с помощью фоторезиста, ЛУТ не проходит т.к. очень мелкая детализация - сд.регистр паялся под лупой.
Программу как-то "написал" на AVR C, используя чужие библиотеки 1wire и примеры находящиеся в свободном доступе(не помню чьи) , просьба не ругать а поправить, ну не получается у меня пока разложить 8битовое значение в Atmel Studio - поэтому побитно делал, знаю что некрасиво...
Проект "запустил" в Протеусе. Перенес в жизнь и вот не работает. Подозреваю что 18в20 не отслеживает температуру (если без датчика индикатор выводит 00 что и нужно, при подключение датчика - 88??) Видно временные интервалы расчитал неправильно. Ну что коты поможете?
http://www.pif-paf.com.ua/img/term.jpg

Изображение

Код: Выделить всё

#include <avr/io.h>
#include <avr/iotn45.h> // библиотека для используемого МК
#include <util/delay.h>
#include <avr/interrupt.h>
#include <avr/wdt.h>

#define F_CPU 8000000UL
#define DATA 2  // Подключаем к порту PB2 ножку данных сдвигового регистра
#define CLK 0    // Подключаем к порту PB0 ножку тактовых импульсов сдвигового регистра
#define RES 1  // Подключаем к порту PB1 ножку защёлки сдвигового регистра
#define TRIG 3   // Подключаем к порту PB3 >100/минус

unsigned char led_buff[13];
unsigned char reg_buff[3];
unsigned char buf_temp[4] = {0,0,0,11};
//общий анод	
const char pinot[7] = {1,1,1,1,1,1,1};    // Точкa 0x7F
const char one[7] = {1,1,1,1,0,0,1};      // Один  0x4F
const char two[7] = {0,1,0,0,1,0,0};      // Два   0x12
const char three[7] = {0,1,1,0,0,0,0};    // Три   0x30
const char four[7] = {0,0,1,1,0,0,1};     // Четыре 0x19
const char five[7] = {0,0,1,0,0,1,0};     // Пять   0x12
const char six[7] = {0,0,0,0,0,1,0};      // Шесть  0x2 
const char seven[7] = {1,1,1,1,0,0,0};    // Семь   0x78
const char eight[7] = {0,0,0,0,0,0,0};      // Восемь 0x0
const char nine[7] = {0,0,1,0,0,0,0};      // Девять  0x04
const char zero[7] = {1,0,0,0,0,0,0};      // Ноль    0x01
const char minus[7] = {0,1,1,1,1,1,1};      // Минус  0x3F	
const char blanc[7] = {1,1,1,1,1,1,1};      // Пусто  0x7F
	
const char reg0[3] = {0,0,0};
const char reg1[3] = {0,1,1};       //Вывод знакомест 	
const char reg2[3] = {1,0,1}; 
const char reg3[3] = {1,1,0};  	

int temp;
	

void takt() {
	PORTB |= _BV(CLK); //установить 1 на PB0
	_delay_us(150);
	PORTB &= ~_BV(CLK); //установить 0 на РВ0
	_delay_us(150);
}
void vpihreg(char digit[3]) {
	unsigned char i;
	for (i=0;i<2;i++) {
		PORTB = (digit[i]<<DATA); // вывод на нужный регистр
		takt();
	}
}


void vpih(char digit[7]) {
	unsigned char i=0;
	for (i=0;i<7;i++) {
		PORTB = (digit[i]<<DATA); // побитный вывод значения на вывод PB2
		takt(); //запуск стробирующего импульса
	}
	if (temp>99) {
	//if (buf_temp[0]<12)	{
		//PORTB |= _BV(TRIG); //установить 1 PB3
		PORTB = (1<<TRIG);
	}
	else {
		//PORTB &= ~_BV(TRIG);//установить 0 PB3
		PORTB = (0<<TRIG);
	}
	PORTB |= _BV(RES); //сигнал защелки на PB1
	_delay_us(200); 
	PORTB &= ~_BV(RES);//снять сигнал защелки на PB1
		
}

void reg_temp(signed char temp) {
buf_temp[0]=12; //пустое место
 
 if (temp<0) {
		temp=-temp;
		buf_temp[0]=11; //знак минуса
	}
if (temp>100) {
		 buf_temp[0]=temp/100;
		 temp=temp-100;
		 buf_temp[1]=temp/10;
		 buf_temp[2]=temp%10;
		} 
	else	
 		{
		 buf_temp[1]=temp/10;
		 buf_temp[2]=temp%10;
 		}
	_delay_ms(100);			 
	return buf_temp;
	_delay_ms(10);
}	

ISR (TIMER1_OVF_vect) {

unsigned char i, z;
for (z=0; z<40; z++) {//поставим задержку на 10сек, а после идет обработка сл.прерывания на измерение - измерение темп.каждые 10сек
	for (i=0;i<3;i++) {
		vpihreg (reg_buff[i]);
		vpih (led_buff[buf_temp[i]]);
		_delay_ms(10);
	}
}
}

ISR (TIMER0_OVF_vect) {
temp = temp_18b20();

if(temp > 1000)//если температура <0
{
	temp = 4096 - temp;
	temp = -temp;
}
reg_temp(temp);
}


int main(void) {

led_buff[0]=zero;
led_buff[1]=one;
led_buff[2]=two;
led_buff[3]=three;
led_buff[4]=four;
led_buff[5]=five;
led_buff[6]=six;
led_buff[7]=seven;
led_buff[8]=eight;
led_buff[9]=nine;
led_buff[10]=pinot;
led_buff[11]=minus;
led_buff[12]=blanc; //0x00;
reg_buff[0]=reg0;
reg_buff[1]=reg1;
reg_buff[2]=reg2;
reg_buff[3]=reg0;
char buffer[16] = "";

DDRB = 0b00001111; //настроить РВ0-4 на вывод PB5- вход
PORTB = 0b00000000;
temp = temp_18b20();

if(temp > 1000)//если температура <0
{
	temp = 4096 - temp;
	temp = -temp;
}

reg_temp(temp);//разложение температуры по знакоместам 123 = 1,2,3 - выводит в buf_temp[3]
TCCR1 = (1<<CS10);//коэф деления 8 смотри даташит стр.89
TCCR0B = (1<<CS01)|(1<<CS00);// коэф деления Таймера 0В 64 см.стр.79
TCNT1=0xf3; // 243 коррекция счетчика на 1 сек (243+1)/1000000Гц*4096(коэф деления)= 1сек
TCNT0 = 0xf3;
TIMSK=(1<<TOIE1)|(1<<TOIE0);// включить таймер на внутренние прерывание
sei(); //разрешение прерываний
while(1){	}
}

Вложения
и.JPG
(95.95 КБ) 1587 скачиваний
7seg_AStudio.zip
Дополнительно проект в atmelStudio
(44.03 КБ) 176 скачиваний
term.zip
Во вложении проект и разводка в Протеусе , библиотеки 1wire исходники на Си , *.hex, *.elf
(219.63 КБ) 175 скачиваний
Последний раз редактировалось drBOR Чт янв 24, 2013 18:23:45, всего редактировалось 2 раза.
Реклама
Вымогатель припоя
Сообщения: 513
Зарегистрирован: Сб фев 19, 2011 18:04:08
Откуда: Татарстан, пос. Актюбинский

Сообщение phanis »

Как вариант можно попробовать подогнать OSCCAL – Oscillator Calibration Register ,хотя с изменением температуры частота все равно будет меняться..
Поэтому нужно сделать авто калибровку обнуляем OSCCAL и пока датчик не отвечает увеличиваем значение OSCCAL.
Контактная информация:
Реклама
Родился
Аватара пользователя
Сообщения: 8
Зарегистрирован: Пн дек 24, 2012 02:56:24

Сообщение drBOR »

phanis писал(а): Поэтому нужно сделать авто калибровку обнуляем OSCCAL и пока датчик не отвечает увеличиваем значение OSCCAL.
изменение регистра OSCCALя думаю актуально только в случае явного влияния температуры на внутрен RС цепочку применить это можно как термозависимость . Ну а вообще это интересная идея(там только изменять кратному 2), но а вдруг частоты запроса по шине отличаются в разы и есть ошибка, тогда это не поможет. Пока не могу представить как это сделать т.к. не решал еще такую задачу кроме как в AVR DUDE.
Определить временные показатели посылки запроса на датчик представляется только по осцилограмме с1-55- все вроде сходится - вопрос - насколько датчик критичен к частоте. Хотя наглядно все нормально, датчик работает неккоректно, по осцилограмме вижу - МК передает зараза 8ки, а не комнатную температуру.
В программе работа только двух прерываний по таймеру первое обслуживает индикатор, а только потом начинает работать программа по второму прерыванию для датчика. Датчик впринципе не может влезть в передачу данных на сд.регистр. У меня еще подозрения что датчик не успевает выйти на рабочий режим, хотя все задержки на имитаторе сг. рекомендаций по 1wire.
Вымогатель припоя
Сообщения: 513
Зарегистрирован: Сб фев 19, 2011 18:04:08
Откуда: Татарстан, пос. Актюбинский

Сообщение phanis »

Нужно определится при какой тактовой будет работать сие устройство. F_CPU объявлено 8000000UL а в протеусе все работает на 1 МГц
тк фьюз делитель на 8 включен и таймеры тож настроены на тактовую в 1МГц. Формировать точные задержки в несколько микросекунд, при низкой тактовой весьма проблематично.
Контактная информация:
Реклама
Эиком - электронные компоненты и радиодетали
Родился
Аватара пользователя
Сообщения: 8
Зарегистрирован: Пн дек 24, 2012 02:56:24

Сообщение drBOR »

phanis писал(а):Нужно определится при какой тактовой будет работать сие устройство. Формировать точные задержки в несколько микросекунд, при низкой тактовой весьма проблематично.
Кабы изначально было решено 1МГц, т.к. подавляюшее большинство однотипных схем по 18в20 привязано к 1МГц. А в тиньке конструктивно вн. делитель не опустить на ту временную задержку с 8МГЦ (???). Т.к. используются 2 таймера то им более подходит 1МГц
Реклама
Вымогатель припоя
Сообщения: 513
Зарегистрирован: Сб фев 19, 2011 18:04:08
Откуда: Татарстан, пос. Актюбинский

Сообщение phanis »

Датчик правильно подключен? http://www.google.ru/imgres?um=1&hl=ru& ... 90&bih=660
http://jt5.ru/image/data/examples/DS18B20-schematic.gif
http://chipenable.ru/index.php/programm ... ast-1.html
В ARES печатной плате 3 пин датчика весит в ввоздухе
По поводу OSCCAL он может плавно изменять частоту.
The CAL[6:0] bits are used to tune the frequency within the selected range. A setting of 0x00
gives the lowest frequency in that range, and a setting of 0x7F gives the highest frequency in the
range.
(OSCCAL 0x00 .. 0xFF) меняет от 50 до 200% от номинальной
Контактная информация:
Реклама
Родился
Аватара пользователя
Сообщения: 8
Зарегистрирован: Пн дек 24, 2012 02:56:24

Сообщение drBOR »

phanis писал(а):Датчик правильно подключен? В ARES печатной плате 3 пин датчика весит в ввоздухе
Прошу прощения забыл указать - Пин VСС датчика специально в воздухе, что бы его по выбору можно было подключить к питанию или земле. По схемам подключения я в курсе:)
phanis писал(а):По поводу OSCCAL он может плавно изменять частоту.
Попробую реализовать это в ближайшее время, может у кого с временем получше, раньше выложит!?
Родился
Аватара пользователя
Сообщения: 8
Зарегистрирован: Пн дек 24, 2012 02:56:24

Сообщение drBOR »

Схему немного переработал, после многочисленных попыток так и не получилось адекватно выводить данные с вывода Q7' сдвигового регистра :(, поэтому применил инвертор добавив еще один транзистор Q2 используя один выход Q7, для выравнивания свечения индикации единицы добавлен R7. Программу максимально переписал, значительно сократив код, теперь она занимает меньше половины флеш. Кроме того включена фунция подстройки калибровочной константы для точной подстройки частоты для работы по протоколу 1wire. Схемка получилась вот такая. Пин VCC датчика подключен на +5в.Изображение
Код вот

Код: Выделить всё

#include <avr/io.h>
#include <avr/iotn45.h> // библиотека для используемого МК
#define F_CPU 8000000UL
#include <util/delay.h>
#include <avr/interrupt.h>
#include <avr/wdt.h>

#define DATA 2  // Подключаем к порту PB2 ножку данных сдвигового регистра
#define CLK 0    // Подключаем к порту PB0 ножку тактовых импульсов сдвигового регистра
#define RES 1  // Подключаем к порту PB1 ножку защёлки сдвигового регистра
#define TRIG 3   // Подключаем к порту PB3 ножку сигнал - вывести данные

//общий анод - ОСНОВНАЯ	таблица символов - данные в 7ми битном значении- нет знака точки
const char led_table[15]={0x2,0x9E,0x24,0xC,0x98,0x48,0x40,0x1E,0x0,0x8,0xFC,0xFE,0xC4,0xD4,0x38};
//		0,      1,     2      3      4	 5      6       7       8     9,минус,пусто, O   N симв.градуса	
int temp; //глобальная переменная значения температуры
unsigned char reg_buff[4]; //временный массив значений знакомест
unsigned char buf_temp[4] = {0,0,0,10}; //массив цифр температуры 10-это минус
unsigned char int_data_end = 1; //переменная признака конца обработки

//стробирующий импульс на сд.регистр
void takt() {
	PORTB |= _BV(CLK); //установить 1 на PB0
	_delay_us(20);
	PORTB &= ~_BV(CLK); //установить 0 на РВ0
	_delay_us(20);
}

// вывод данных о знакоместе на сд.регистр - два знакоместа
void send_reg2(unsigned char reg)
{
	for(unsigned char i = 0; i<2; i++)//в цикле посылаем побитно
	{
		if((reg & (2>>i)) == 2>>i)//если бит=1 посылаем 1
		{
			PORTB = (1<<DATA);
			takt(); //запуск стробирующего импульса
		}
		else//иначе посылаем 0
		{
			PORTB = 0<<DATA;
			takt(); //запуск стробирующего импульса
		}
	}
}

// функция вывода символа(цифры) на сдвиговый регистр
void send_data (unsigned char digit) {
	for(unsigned char i = 1; i <8; i++)//в цикле посылаем побитно
	{
		if((digit & (1<<i)) == 1<<i)//если бит=1 посылаем 1
		{
			//PORTB &= ~(1<<DATA);
			PORTB = (1<<DATA);
			takt(); //запуск стробирующего импульса
		}
		else//иначе посылаем 0
		{
			//PORTB |= 1<<DATA;
			PORTB = 0<<DATA;
			takt(); //запуск стробирующего импульса
		}
	}
	if (temp>99) { //вывод еденицы при температуре более 100гр
			//PORTB |= _BV(TRIG); //установить 1 PB3		
			PORTB = (1<<TRIG);
		}
		else {
			PORTB = (0<<TRIG);
	}
	_delay_us(5);
	PORTB |= _BV(RES); //сигнал защелки на PB1
	_delay_us(20);
	PORTB &= ~_BV(RES);//снять сигнал защелки на PB1
}

//функция разложения значения температуры на сотни.десятки.еденицы градусов
unsigned char reg_temp(signed char temp) {
buf_temp[0]=11; //пустое место
 if (temp<0) {
		temp=-temp;
		buf_temp[0]=10; //знак минуса
		}
 if (temp>100) {
		 buf_temp[0]=temp/100; //деление на целое если >100 то 1
		 temp=temp-100;
		 buf_temp[1]=temp/10; //выделение десятков
		 buf_temp[2]=temp%10; //остаток от деления еденицы градусов
		} 
  else	
 		{
		 buf_temp[1]=temp/10; //выделение десятков
		 buf_temp[2]=temp%10; //остаток от деления еденицы градусов
 		}
	_delay_ms(10);			 
	return buf_temp; //возвращает разложенные значения температуры 123 = {1,2,3}
	//_delay_ms(10);
}	

//вывод символов включения ON
void device_ON(){
	for (char i=12;i<14;i++) {
		send_reg2(i-11); //вывод знакоместа
		send_data (led_table[i]);//выводим значение
		_delay_ms(2); //задержка между посылками
	}
}

//прерывание по 1му таймеру
ISR (TIMER1_OVF_vect) {
int_data_end = 1;
unsigned char i, z;
for (z=0; z<20; z++) {//2 на 0.2сек//40 поставим задержку на 10сек, а после идет обработка сл.прерывания на измерение - измерение темп.каждые 10сек
	for (i=1;i<3;i++) {
		//обнуление индикаторов
		/*if (i==1){
		send_reg2(0);
		send_data(led_table[8]);
		_delay_ms(1);
		}*/
		send_reg2(i); //вывод знакоместа
		send_data(led_table[buf_temp[i]]);//выводим значения
		_delay_ms(2); //задержка между посылками 
	}
}
int_data_end = 0;
}

//прерывание по 0таймеру
/*ISR (TIMER0_OVF_vect) {
//calibrating_osccal(); //калибровка константы osccal -  если невозможно связаться с уст.1wire
temp = temp_18b20();

if(temp > 1000)//если температура <0
{
	temp = 4096 - temp;
	temp = -temp;
}
reg_temp(temp);
}*/

int main(void) {

DDRB = 0b00001111; //настроить РВ0-4 на вывод PB5- вход
PORTB = 0b00000000;



temp = temp_18b20();
if(temp > 1000)//если температура <0
{
	temp = 4096 - temp;
	temp = -temp;
}
reg_temp(temp);//разложение температуры по знакоместам 123 = 1,2,3 - выводит в buf_temp[3]
device_ON();//вывод сигнала ON - при включении
TCCR1 = (1<<CS13)|(1<<CS12)|(1<<CS10);
TCCR0B = (1<<CS01)|(1<<CS00);// коэф деления Таймера 0В 64 см.стр.79
TCNT1=0xf3; // 243 коррекция счетчика на 1 сек (243+1)/1000000Гц*4096(коэф деления)= 1сек
TCNT0 = 0xf3;
TIMSK=(1<<TOIE1)|(1<<TOIE0);// включить таймер на внутренние прерывание
sei(); //разрешение прерываний
while(1){
	if (int_data_end == 0)	{
		TCNT1=0xf3;
		TIMSK= (1<<TOIE1);
		//обнуление и вывод символа градуса
		send_reg2(0);
		send_data(led_table[14]);
		temp = temp_18b20();
		
		if(temp > 1000)//если температура <0
		{
			temp = 4096 - temp;
			temp = -temp;
		}

		reg_temp(temp);
	}
}
}
Ну и сборка проекта в Протеусе, исходники и *.hex Все работает!
Вложения
term.zip
(209.41 КБ) 201 скачивание
Ответить

Вернуться в «AVR»