AtTiny13a, DS1307 и оптимизация кода

Обсуждаем контроллеры компании Atmel.
Ответить
Открыл глаза
Аватара пользователя
Сообщения: 59
Зарегистрирован: Сб окт 06, 2012 15:12:19
Откуда: Орел

Сообщение Siper »

Доброго всем дня. Очень прошу помощи в оптимизации кода для AtTiny13a. Есть устройство на AtMega8, которое в определенное время не включает нагрузку (например, если ночью выключили электричество, а потом включили). Оно отлично работает, но моя внутренняя жаба говорит, что atmega8 для общения с DS1307 и одного внешнего прерывания - это слишком. Решил я перенести проект на AtTiny13, все хорошо, но только не могу уместить код в 1 кб, интуиция подсказывает, что можно как-то оптимизировать функции программного I2C. Возможно кто-то подскажет, как можно оптимизировать это? Или даже не стоит пытаться запихнуть программный I2C и внешнее прерывание в этот мк? Прилагаю код и проект в Atmel Studio 6.2.
Спойлер

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

#define F_CPU 9600000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

#define QDEL _delay_loop_2(3)
#define HDEL _delay_loop_2(5)

#define I2C_PORT PORTB
#define I2C_PIN PINB
#define I2C_DDR DDRB

#define SDA PB3
#define SCL PB4

#define SCL_LOW I2C_DDR|=((1<<SCL))
#define SCL_HIGH I2C_DDR&=(~(1<<SCL))

#define SDA_LOW I2C_DDR|=((1<<SDA))
#define SDA_HIGH I2C_DDR&=(~(1<<SDA))

#define RTC_ADR 0x68

#define SEC_ADR 0x00
#define MIN_ADR 0x01
#define HOUR_ADR 0x02
#define DAY_ADR 0x04
#define MONTH_ADR 0x05
#define YEAR_ADR 0x06

#define LED PB0
#define PIN_INT0 PB1
#define RELAY PB2

#define RELAY_ON PORTB|=((1<<RELAY))
#define RELAY_OFF PORTB&=(~(1<<RELAY))
#define LED_ON PORTB|=((1<<LED))
#define LED_OFF PORTB&=(~(1<<LED))

volatile uint8_t button_flag;

void I2C_Init(void);
void I2C_Start(void);
void I2C_Stop(void);
uint8_t I2C_WriteByte(uint8_t data);
uint8_t I2C_ReadByte(uint8_t ack);
uint8_t RTC_Read(uint8_t adr);
void RTC_Write(uint8_t adr, uint8_t data);
void RTC_SetValue(uint8_t val, uint8_t adr);
static uint8_t RTC_ReadValue(uint8_t adr);

ISR(INT0_vect)
{
	button_flag = 1;
	_delay_ms(500);
}

int main(void)
{
	uint8_t hour = 0;
	button_flag = 0;
	DDRB = 0xff;
	I2C_Init();
	DDRB &= ~(1<<PIN_INT0);
	PORTB |= (1<<PIN_INT0);									  // Включаем подтягивающий резистор
	GIMSK |= (1<<INT0);										  // Разрешаем внешнее прерывание на int0
	MCUCR &= ~(1<<ISC01)|(1<<ISC00);						  // Настраиваем условие прерывания
	LED_ON;
	RELAY_OFF;
	sei();
	while((hour > 0x10 && hour < 0x22) || button_flag == 1)
	{
		hour = RTC_Read(HOUR_ADR);
		_delay_ms(300);
	}
	button_flag = 0;
	cli();
    while(1)
    {
		LED_OFF;
        RELAY_ON;
    }
}

void I2C_Init(void)
{
	uint8_t i;
	I2C_PORT&=(1<<SDA);
	I2C_PORT&=(1<<SCL);
	for(i=0;i<10;i++)
	{
		SCL_HIGH;
		HDEL;
		SCL_LOW;
		HDEL;
	}
	SDA_HIGH;
	SCL_HIGH;
}

void I2C_Start(void)
{
	SCL_HIGH;
	HDEL;
	SDA_LOW;
	HDEL;
}

void I2C_Stop(void)
{
	SDA_LOW;
	HDEL;
	SCL_HIGH;
	QDEL;
	SDA_HIGH;
	HDEL;
}

uint8_t I2C_WriteByte(uint8_t data)
{
	uint8_t i;
	for(i=0;i<8;i++)
	{
		SCL_LOW;
		QDEL;
		if(data & 0x80)
		SDA_HIGH;
		else
		SDA_LOW;
		HDEL;
		SCL_HIGH;
		HDEL;
		while((I2C_PIN & (1<<SCL))==0);
		data=data<<1;
	}
	SCL_LOW;
	QDEL;
	SDA_HIGH;
	HDEL;
	SCL_HIGH;
	HDEL;
	uint8_t ack=!(I2C_PIN & (1<<SDA));
	SCL_LOW;
	HDEL;
	return ack;
}

uint8_t I2C_ReadByte(uint8_t ack)
{
	uint8_t data=0x00;
	uint8_t i;
	for(i=0;i<8;i++)
	{
		SCL_LOW;
		HDEL;
		SCL_HIGH;
		HDEL;
		while((I2C_PIN & (1<<SCL))==0);
		if(I2C_PIN &(1<<SDA))
		data|=(0x80>>i);
	}
	SCL_LOW;
	QDEL;
	if(ack)
	{
		SDA_LOW;
	}
	else
	{
		SDA_HIGH;
	}
	HDEL;
	SCL_HIGH;
	HDEL;
	SCL_LOW;
	HDEL;
	return data;
}

uint8_t RTC_Read(uint8_t adr)
{
	uint8_t ack, data;
	I2C_Start();
	ack = I2C_WriteByte((RTC_ADR<<1)|0);
	if(!ack) return 0;
	ack = I2C_WriteByte(adr);
	if(!ack) return 0;
	I2C_Start();
	ack = I2C_WriteByte((RTC_ADR<<1)|1);
	data = I2C_ReadByte(0);
	I2C_Stop();
	return data;
}

void RTC_Write(uint8_t adr, uint8_t data)
{
	uint8_t ack;
	I2C_Start();
	ack = I2C_WriteByte((RTC_ADR<<1)|0);
	if(!ack) return;
	ack = I2C_WriteByte(adr);
	if(!ack) return;
	ack = I2C_WriteByte(data);
	if(!ack) return;
	I2C_Stop();
}

void RTC_SetValue(uint8_t val, uint8_t adr)
{
	val = ((val/10) << 4)|(val%10);
	RTC_Write(adr, val);
}

uint8_t RTC_ReadValue(uint8_t adr)
{
	uint8_t value;
	value = RTC_Read(adr);
	value = (((value&0xF0)>>4)*10)+(value&0x0F);
	return value;
}
Relay_attiny13.rar
Проект в Atmel Studio 6.2
(22.12 КБ) 156 скачиваний
Последний раз редактировалось Siper Вс янв 31, 2016 14:55:52, всего редактировалось 1 раз.
Контактная информация:
Реклама
Опытный кот
Сообщения: 804
Зарегистрирован: Чт мар 12, 2009 16:31:05

Сообщение Vov123 »

"Прилогаю" - красивое слово, однако.


По существу, вероятно без ассемблера не обойтись.
Будет интересно: Ю.Ревич "Практическое программирование микроконтроллеров Atmel AVR на языке ассемблера" 2008г.
стр.273 Ваш случай.
Реклама
Открыл глаза
Аватара пользователя
Сообщения: 59
Зарегистрирован: Сб окт 06, 2012 15:12:19
Откуда: Орел

Сообщение Siper »

Vov123 писал(а):"Прилогаю" - красивое слово, однако.


По существу, вероятно без ассемблера не обойтись.
Будет интересно: Ю.Ревич "Практическое программирование микроконтроллеров Atmel AVR на языке ассемблера" 2008г.
стр.273 Ваш случай.
Спасибо, исправил. Мало того, что программировать не умею еще и с русским проблемы. Спасибо за литературу, буду изучать. Неужели без ассемблера никак?
Контактная информация:
Опытный кот
Сообщения: 804
Зарегистрирован: Чт мар 12, 2009 16:31:05

Сообщение Vov123 »

Возьмите тиньку2313, там памяти в 2 раза больше.

Там книга есть более позднего выхода, страницы могут не совпадать, а так, одно и тоже.
Реклама
Эиком - электронные компоненты и радиодетали
akl
Друг Кота
Сообщения: 4463
Зарегистрирован: Пт мар 07, 2008 06:54:43
Откуда: Ижевск

Сообщение akl »

Siper писал(а): atmega8 для общения с DS1307 и одного внешнего прерывания - это слишком. Решил я перенести проект на AtTiny13...Возможно кто-то подскажет, как можно оптимизировать это?..
Оптимизацию можно начать выкинув DS1307. Задать частоту 128кГц, всю работу по отсчёту времени возложить на таймер.
Реклама
Открыл глаза
Аватара пользователя
Сообщения: 59
Зарегистрирован: Сб окт 06, 2012 15:12:19
Откуда: Орел

Сообщение Siper »

akl писал(а):Оптимизацию можно начать выкинув DS1307. Задать частоту 128кГц, всю работу по отсчёту времени возложить на таймер.
Дело в том, что устройство должно запускаться после выключения электроэнергии и проверять время, поэтому и выбрана DS1307.
Выкинул функцию задержки, без нее на моем отладочном стенде все работает, получился размер hex файла 1,04 кб. Может ещё что-нибудь можно сделать?
Спойлер

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

#define F_CPU 9600000UL
#include <avr/io.h>
#include <avr/interrupt.h>

#define I2C_PORT PORTB
#define I2C_PIN PINB
#define I2C_DDR DDRB

#define SDA PB3
#define SCL PB4

#define SCL_LOW I2C_DDR|=((1<<SCL))
#define SCL_HIGH I2C_DDR&=(~(1<<SCL))

#define SDA_LOW I2C_DDR|=((1<<SDA))
#define SDA_HIGH I2C_DDR&=(~(1<<SDA))

#define RTC_ADR 0x68

#define SEC_ADR 0x00
#define MIN_ADR 0x01
#define HOUR_ADR 0x02
#define DAY_ADR 0x04
#define MONTH_ADR 0x05
#define YEAR_ADR 0x06

#define LED PB0
#define PIN_INT0 PB1
#define RELAY PB2

#define RELAY_ON PORTB|=((1<<RELAY))
#define RELAY_OFF PORTB&=(~(1<<RELAY))
#define LED_ON PORTB|=((1<<LED))
#define LED_OFF PORTB&=(~(1<<LED))

volatile uint8_t button_flag;

void I2C_Init(void);
void I2C_Start(void);
void I2C_Stop(void);
uint8_t I2C_WriteByte(uint8_t data);
uint8_t I2C_ReadByte(uint8_t ack);
uint8_t RTC_Read(uint8_t adr);
void RTC_Write(uint8_t adr, uint8_t data);

ISR(INT0_vect)
{
	button_flag = 1;
}

int main(void)
{
	uint8_t hour = 0;
	button_flag = 0;
	DDRB = 0xff;
	I2C_Init();
	DDRB &= ~(1<<PIN_INT0);
	PORTB |= (1<<PIN_INT0);									  // Включаем подтягивающий резистор
	GIMSK |= (1<<INT0);										  // Разрешаем внешнее прерывание на int0
	MCUCR &= ~(1<<ISC01)|(1<<ISC00);						  // Настраиваем условие прерывания
	LED_ON;
	RELAY_OFF;
	sei();
	while((hour > 0x10 && hour < 0x22) || button_flag == 1)
	{
		hour = RTC_Read(HOUR_ADR);
	}
	button_flag = 0;
	cli();
    while(1)
    {
		LED_OFF;
        RELAY_ON;
    }
}

void I2C_Init(void)
{
	uint8_t i;
	I2C_PORT&=(1<<SDA);
	I2C_PORT&=(1<<SCL);
	for(i=0;i<10;i++)
	{
		SCL_HIGH;
		SCL_LOW;
	}
	SDA_HIGH;
	SCL_HIGH;
}

void I2C_Start(void)
{
	SCL_HIGH;
	SDA_LOW;
}

void I2C_Stop(void)
{
	SDA_LOW;
	SCL_HIGH;
	SDA_HIGH;
}

uint8_t I2C_WriteByte(uint8_t data)
{
	uint8_t i;
	for(i=0;i<8;i++)
	{
		SCL_LOW;
		if(data & 0x80)
		SDA_HIGH;
		else
		SDA_LOW;
		SCL_HIGH;
		while((I2C_PIN & (1<<SCL))==0);
		data=data<<1;
	}
	SCL_LOW;
	SDA_HIGH;
	SCL_HIGH;
	uint8_t ack=!(I2C_PIN & (1<<SDA));
	SCL_LOW;
	return ack;
}

uint8_t I2C_ReadByte(uint8_t ack)
{
	uint8_t data=0x00;
	uint8_t i;
	for(i=0;i<8;i++)
	{
		SCL_LOW;
		SCL_HIGH;
		while((I2C_PIN & (1<<SCL))==0);
		if(I2C_PIN &(1<<SDA))
		data|=(0x80>>i);
	}
	SCL_LOW;
	if(ack)
	{
		SDA_LOW;
	}
	else
	{
		SDA_HIGH;
	}
	SCL_HIGH;
	SCL_LOW;
	return data;
}

uint8_t RTC_Read(uint8_t adr)
{
	uint8_t ack, data;
	I2C_Start();
	ack = I2C_WriteByte((RTC_ADR<<1)|0);
	if(!ack) return 0;
	ack = I2C_WriteByte(adr);
	if(!ack) return 0;
	I2C_Start();
	ack = I2C_WriteByte((RTC_ADR<<1)|1);
	data = I2C_ReadByte(0);
	I2C_Stop();
	return data;
}

void RTC_Write(uint8_t adr, uint8_t data)
{
	uint8_t ack;
	I2C_Start();
	ack = I2C_WriteByte((RTC_ADR<<1)|0);
	if(!ack) return;
	ack = I2C_WriteByte(adr);
	if(!ack) return;
	ack = I2C_WriteByte(data);
	if(!ack) return;
	I2C_Stop();
}
Контактная информация:
Реклама
Электрический кот
Аватара пользователя
Сообщения: 1031
Зарегистрирован: Чт июн 20, 2013 00:00:58
Откуда: москва, м.Сходненская

Сообщение Mishany »

Device: attiny13a
Program: 644 bytes (62.9% Full)
(.text + .data + .bootloader)
Data: 1 bytes (1.6% Full)
(.data + .bss + .noinit)
или я чего то не догоняю?
Открыл глаза
Аватара пользователя
Сообщения: 59
Зарегистрирован: Сб окт 06, 2012 15:12:19
Откуда: Орел

Сообщение Siper »

Mishany писал(а):Device: attiny13a
Program: 644 bytes (62.9% Full)
(.text + .data + .bootloader)
Data: 1 bytes (1.6% Full)
(.data + .bss + .noinit)
или я чего то не догоняю?
Прошу прощения за глупость свою, смотрел на размер hex. Всем спасибо, тему можно удалять наверное.
Контактная информация:
Друг Кота
Аватара пользователя
Сообщения: 15677
Зарегистрирован: Вт мар 16, 2010 22:02:27
Откуда: ДОНЕЦК

Сообщение BOB51 »

Перенеси проект на attiny45(85) - там с аппаратной "начинкой" поудобнее и памяти больше.
:roll:
Ответить

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