Скачиваний:
0
Добавлен:
12.02.2026
Размер:
8.16 Кб
Скачать
/*
*	Маленькое предисловие. Я не знаю почему, но
*	данный код не корректно работает с МК ATtiny104,
*	если в настройках компилятора поставить обычную оптимизацию
*	оптимизацию (-O1). Работает только с оптимизацией по
*	памяти (-Os). Возможно это связано с нехваткой стека
*	или какими-то особенностями самого МК. Проверить это я
*	не могу, да и мне не сильно хочется. Как говорится:
*	"Если работает - не трогай", я так и сделаю и вам советую.
*/

#include <avr/io.h>
#define F_CPU 8000000ul
#include <util/delay.h>
#include <avr/interrupt.h>

#define LED_Count 4
#define Color_Count 3

typedef struct{ // Мтруктура диодов
	uint8_t Blue;
	uint8_t Red;
	uint8_t Green;
	uint8_t Phase;
} LED;

LED leds[LED_Count] = { 0 }; // Инициализация массива
	
uint8_t LED_mode = 0; // Отвечает за режим работы
uint8_t ModChangeFlag = 1; // Флаг изменения режима
uint8_t LedsMask = 0; // Маска числа для счёта

void send_1(){ // Отправка 1
	PORTA = (1 << PORTA6); // HIGH сигнал
	asm __volatile__("nop;\n nop;\n nop;\n nop;"); // Ожидание 4 такта
	PORTA = 0; // LOW сигнал
	asm __volatile__("nop;"); // Ожидание 1 такт
}

void send_0(){ // Отправка 0
	PORTA = (1 << PORTA6); // HIGH сигнал
	asm __volatile__("nop;"); // Ожидание 1 такт
	PORTA = 0; // LOW сигнал
	asm __volatile__("nop;\n nop;\n nop;\n nop;"); // Ожидание 4 такта
}

void send_color(uint8_t color) // Сравнение битов в коде цвета
{
	for (uint8_t i = 0; i < 8 ; i++) // Перебор битов
	{
		if (color & (1 << 7)) //Если последний бит 1
		{
			send_1(); // Отправляем 1
		}
		else
		{
			send_0(); // Иначе отправляем ноль
		}
		color <<= 1; // Сдвигаем вправо код цвета
	}
}

void send_data(){ // Отправка данных на диоды
	for (uint8_t i = 0; i < LED_Count; i++) // Для каждого из диодов
	{
		send_color(leds[i].Green); // Зелёный цвет
		send_color(leds[i].Red); // Красный цвет
		send_color(leds[i].Blue); // Синий цвет
	}
	_delay_us(60); // Пауза, что закончили передачц
}

void led_init(){
	switch (LED_mode) // В зависимости от режима
	{
		case 0: // Диоды выключены
			for(uint8_t i = 0; i < LED_Count; i++) // Инициализация диодов
			{
				leds[i].Green = 0x00; // Зелёный 0
				leds[i].Red = 0x00; // Красный 0
				leds[i].Blue = 0x00; // Синий 0
			}
			break;
		case 1: // Тухлый свет
			for(uint8_t i = 0; i < LED_Count; i++) // Инициализация диодов
			{
				leds[i].Green = 0x20; // Зелёный тускло
				leds[i].Red = 0x20; // Красный тускло
				leds[i].Blue = 0x20; // Синий тускло
			}
			break;
		case 2: // Яркий свет
			for(uint8_t i = 0; i < LED_Count; i++) // Инициализация диодов
			{
				leds[i].Green = 0xFF; // Зелёный ярко
				leds[i].Red = 0xFF; // Красный ярко
				leds[i].Blue = 0xFF; // Синий ярко
			}
			break;
		// Дальше отдельно забивали каждый диод, чтобы сэкономить место в памяти
		case 3: // Счёт
			leds[0].Green = 0x00; // Зелёный 0
			leds[0].Red = 0x00; // Красный 0
			leds[0].Blue = 0x00; // Синий 0
			leds[0].Phase = 0;
			
			leds[1].Green = 0x00; // Зелёный 0
			leds[1].Red = 0x00; // Красный 0
			leds[1].Blue = 0x00; // Синий 0
			leds[1].Phase = 0;
			
			leds[2].Green = 0x00; // Зелёный 0
			leds[2].Red = 0x00; // Красный 0
			leds[2].Blue = 0x00; // Синий 0
			leds[2].Phase = 0;
			
			leds[3].Green = 0x00; // Зелёный 0
			leds[3].Red = 0x00; // Красный 0
			leds[3].Blue = 0x00; // Синий 0
			leds[3].Phase = 0;
			break;
		case 4: // Синхронная радуга
			leds[0].Green = 0x00; // Зелёный 0
			leds[0].Red = 0xFF; // Красный 0
			leds[0].Blue = 0x00; // Синий 0
			leds[0].Phase = 0;
			
			leds[1].Green = 0x00; // Зелёный 0
			leds[1].Red = 0xFF; // Красный 0
			leds[1].Blue = 0x00; // Синий 0
			leds[1].Phase = 0;
			
			leds[2].Green = 0x00; // Зелёный 0
			leds[2].Red = 0xFF; // Красный 0
			leds[2].Blue = 0x00; // Синий 0
			leds[2].Phase = 0;
			
			leds[3].Green = 0x00; // Зелёный 0
			leds[3].Red = 0xFF; // Красный 0
			leds[3].Blue = 0x00; // Синий 0
			leds[3].Phase = 0;
			break;
		case 5: // Асинхронная радуга
			leds[0].Green = 0x00; // Зелёный 0
			leds[0].Red = 0xFF; // Красный 0
			leds[0].Blue = 0x00; // Синий 0
			leds[0].Phase = 0;
			
			leds[1].Green = 0xFF; // Зелёный 0
			leds[1].Red = 0xFF; // Красный 0
			leds[1].Blue = 0x00; // Синий 0
			leds[1].Phase = 1;
			
			leds[2].Green = 0xFF; // Зелёный 0
			leds[2].Red = 0x00; // Красный 0
			leds[2].Blue = 0x00; // Синий 0
			leds[2].Phase = 2;
			
			leds[3].Green = 0xFF; // Зелёный 0
			leds[3].Red = 0x00; // Красный 0
			leds[3].Blue = 0xFF; // Синий 0
			leds[3].Phase = 3;
			break;
	}
}

int main(void)
{
	// Инициализация пинов
	DDRA |= (1 << DDRA6); // Пин А6 - выход
	PORTA &= ~(1 << PORTA6); // На выходе по умолчанию 0
	DDRB &= ~(1 << DDRB1); // Пин B1 - вход
	PUEB |= (1 << PUEB1); // Подтяжка В1
	
	// Настройка прерывания по изменению уровня
	PCICR |= (1 << PCIE1)|(0 << PCIE0);  // Включение прерывания по изменению состояния на 1 для группы B
	PCMSK1 |= (1 << PCINT9); // Определяем что это будет именно для B1 (там где кнопка)
	
	CCP = 0xD8; // Разблокируем настройки процессора
	CLKPSR = 0; // Предделитель процессора 0
	
	sei(); // Разрешаем Глоб. Прерывания
	
	while(1) // Бесконечный цикл
	{
		if(ModChangeFlag){ // Проверяем было ли переключение режимов
			led_init(); // Запускаем инициацию
			ModChangeFlag = 0; // Сбразываем флаг
		}
		if (LED_mode == 3){ // Если режим счёта
			leds[0].Phase++; // Увеличиваем число
			if (leds[0].Phase == 16) // Если вышли за рамки
			{
				leds[0].Phase = 0; // Сбрасываем к нулю
			} // P.S. Вообще, это можно было не делать и сэкономить память
			LedsMask = 1; // Маска, для определения какие диоды зажигать
			for(uint8_t i = 0; i < LED_Count; i++) // Инициализация диодов
			{
				if (LedsMask & leds[0].Phase) // Если маска и бит в фазе
				{ // совпадают, то зажигаем диод на чут-чут
					leds[i].Red = 0x20;
					leds[i].Blue = 0x20;
					leds[i].Green = 0x20;
				} // Иначе гасим
				else {
					leds[i].Red = 0x00;
					leds[i].Blue = 0x00;
					leds[i].Green = 0x00;
				}
				LedsMask <<= 1; // Сдвигаем маску влево
			}
			_delay_ms(450); // Паузу, чтобы не офигевать от скорости
		}
		if((LED_mode == 4)|(LED_mode == 5)){ // Режимы радуги
			for(uint8_t i = 0; i < LED_Count; i++) // инициализация диодов
			{
				switch (leds[i].Phase){ // Проверяем фазу
					case 0: // Красный -> Оранжевый -> Жёлтый 
						if(leds[i].Green == 0xFF){ //Проверяем верх
							leds[i].Phase++; //Если достигли - след. фаза
						}
						else{ // Иначе - ВСЁ НА ЗЕЛЁНОЕ!
							leds[i].Green++; 
						}
						break;
					case 1: // Жёлтый -> Зелёный
						if(leds[i].Red == 0){ // Тут по аналогии
							leds[i].Phase++; // Но уменьшаем красный
						}
						else{
							leds[i].Red--;
						}
						break;
					case 2: // Зелёный -> Голубой
						if(leds[i].Blue == 0xFF){
							leds[i].Phase++;
						}
						else{
							leds[i].Blue++;
						}
						break;
					case 3: // Голубой -> Синий
						if(leds[i].Green == 0){
							leds[i].Phase++;
						}
						else{
							leds[i].Green--;
						}
						break;
					case 4: // Синий -> Фиолетовый
						if(leds[i].Red == 0xFF){
							leds[i].Phase++;
						}
						else{
							leds[i].Red++;
						}
						break;
					case 5: // Фиолетовый -> Красный
						if(leds[i].Blue == 0){ // Сбрасываем фазу
							leds[i].Phase = 0; // т.к. она последняя
						}
						else{
							leds[i].Blue--;
						}
						break;
				}
			}
		}
		send_data(); // Отправляем данные на диоды
		_delay_ms(5); // Пауза, чтобы не слишком быстро было
	}
}

ISR(PCINT1_vect) { // Перывание по нажатию любимой кнопочки
	cli(); // Отключим прерывания, а вдруг что?
	if(PINB & (1 << PINB1)){ // Если кнопку отжали
		LED_mode ++; // Следующий режим
		if (LED_mode == 6) // Проверка номера
		{ // режима, так как у нас их всего 5
			LED_mode = 0; // Сбрасываем режим
		}
		ModChangeFlag = 1; // Ставим флаг, что
	} // переключили режим (для основного цикла)
	sei(); // Включили обратно прерывания
}
Соседние файлы в папке Smart_LED_C_3