Добавил:
koba004
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:Лабы / Сверхлаба / Smart_LED_C_3 / main
.c/*
* Маленькое предисловие. Я не знаю почему, но
* данный код не корректно работает с МК 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
