XLAN

Информация о пользователе

Привет, Гость! Войдите или зарегистрируйтесь.


Вы здесь » XLAN » Микроконтроллеры AVR » Программирование AVR


Программирование AVR

Сообщений 1 страница 10 из 13

1

Всё о программировании микроконтроллеров AVR.
Языки программирования, основные команды, компиляторы и т.д.

2

Для того, чтобы заниматься микроконтроллерами, необязательно хорошо знать языки программирования (я вообще с нуля начинал). Зная немного команд, уже можно многое сделать на МК.
МК я программирую на Си (про Си можно почитать тут: http://lib.ru/CTOTOR/starterkit.txt ) и использую среду разработки - CodeVisionAVR. Тут я напишу немного из основного. Так как я только начал этим заниматься, поэтому пишу так, как понял это я сам (и пишу впервую очередь для себя, чтобы не забыть :) )

Для начала запомним, что в конце команды надо ставить знак ; (точка с запятой)
Всё, что написано после знака // игнорируется компилятором. Это используется для комментирования строчек, чтобы не забыть, что эта строчка делает (комментировать обязательно, иначе даже в простой программе можно запутаться).
Программные модули беруться вот в такие скобки:  { }
 
#include <mega8.h> - Это мы выбрали заголовочный файл, в котором содержится информация об выбраном микроконтроллере (достаточно в CodeVisionAVR выбрать нужный микроконроллер и эта команда впишется автоматически). Эта команда пишется в самом начале. В данном примере выбран файл для ATmega8

#include <delay.h> - Инициализация задержки.

void main(void) - Программный модуль (если не ошибаюсь :) )

int i = Назначение переменной (об этом надо написать отдельно, и разобраться подробней, но пока просто пишем вот так)

Можно назначить определённые порты, чтобы на них был выход 5 вольт. Это полезно например для подключения светодиодов. Если этого не делать, то на выходах будет слабый сигнал.

PORTD=0x00;  - Выставляем все выходы порта D на 0, то есть, выключаем весь порт D

DDRD=0xFF; - Делаем порт D, как выход, чтобы на выходах порта было напряжение 5В

while (1) - Цикл (пока истинно)

Если нужно, чтобы на выходе 0 порта D появился сигнал, пишем:
PORTD.0=1; //На выходе 0 порта D появляется сигнал.

Чтобы выключить сигнал на выходе 0 порта D пишем:
PORTD.1=1; //Выключаем сигнал на выходе 0 порта D.

delay - Задержка
Пример:
delay_ms (250); //Задержка 250 миллисекунд

Вот пример программы, для моргания светодиодом:

#include <mega8.h>
#include <delay.h>
// Declare your global variables here

void main(void)
{
int i; // описание переменной "і" как целое число Int - (Integer)
PORTD=0x00; //Выставляем все выходы порта D на 0, то есть, выключаем весь порт D
DDRD=0xFF; //Делаем порт D, как выход, чтобы на выходах порта было напряжение 5В

while (1) // Основной цикл
    {
    PORTD.0=1; // Зажигаем светодиод на выходе 1 порта D
    delay_ms (300); // Задержка 300 миллисекунд
    PORTD.0=0; // Выключаем светодиод на выходе 0 порта D
    delay_ms (200); // Задержка 200 миллисекунд.
    }
    };
// На начало программы

Идём двльше.

Следует помнить, что на языке Си знак = это не знак равенства, а присвоение значения. Знак равенства пишется вот так: ==
Программа состоит из операторов. Операторы могут быть простыми (как в примере выше) и сложными.

Сложные операторы:
Оператор И
Например: Если сигнал на выходе 0 порта D И на выходе 1 порта D, то... 
Записывается вот так: (условие11 && условие2) Например: (PORTD.0=1 && PORTD.1=1)
Оператор ИЛИ
Например: Если сигнал на выходе 0 порта D ИЛИ на выходе 1 порта D, то...
Записывается вот так: (условие11 || условие2) Например: (PORTD.0=1 || PORTD.1=1)
Оператор НЕ
Напрмер: Если сигнал НЕ на выходе 0 порта D, то...
Записывается так: (! условие1) Например: (! PORTD.0=1)

Некоторые сокращения для операторов присваивания:

x = x + 1 (присвоить переменной x значение больше на 1). Сокращенно это будет так: x++ (или ++x)
x = x - 1 (присвоить переменной x значение меньше на 1). Сокращенно: x-- (или --x)
x = x +y (прибавить y) Сокращённо: x += y
x = x * y (умножить на y) Сокращённо: x * =y
x = x / y (разделить на y) Сокращенно: x /= y

for -  Цикл (в основном служит для выполнения определённого действия несколько раз).
Пример:

for (i = 0; i<15 ; i++) // Повторяем цикл до тех пор, пока i меньше 15 (i++ - i с кадым разом увеличивается на 1)
    {
    PORTD.0=1ж // Зажигаем светодиод на выходе 0 порта D
    delay_ms(300); // Задержка 300 мс
    PORTD.1=1; // Зажигаем светодиод на выходе 1 порта D
    delay_ms(300); // Задержка 300 мс
    PORTD.0=0; // Выключаем светодиод на выходе 0 порта D
    delay_ms (300); // Задержка 300 мс
    PORTD.1=0; Выключаем светодиод на выходе 1 порта D
    delay_ms (300); // Задержка 300 мс
    }

3

Для всяких "бегущих огней" программу можно записывать в таком виде:

PORTD = 0b00000001; // 0 - светодиод выключен, 1 - светодиод включен.
delay_ms (200); // Задержка 200 мс
PORTD = 0b00000011;
delay_ms (200);
PORTD = 0b00000111;
delay_ms (200);
PORTD = 0b00001111;
delay_ms (200);
PORTD = 0b00011111;
delay_ms (200);
PORTD = 0b00111111;
delay_ms (200);
PORTD = 0b01111111;
delay_ms (200);
PORTD = 0b11111111;
delay_ms (200);
PORTD = 0b11111110;
delay_ms (200);
PORTD = 0b11111100;
delay_ms (200);
PORTD = 0b11111000;
delay_ms (200);
PORTD = 0b11110000;
delay_ms (200);
PORTD = 0b11100000;
delay_ms (200);
PORTD = 0b11000000;
delay_ms (200);
PORTD = 0b10000000;
delay_ms (200);
PORTD = 0b00000000;
delay_ms (200);

Тоесть мы сразу включаем несколько светодиодов.
Но так-же можно использовать массив.
Вот так выглядит программа с использованием массива:

#include <mega8.h>
#include <delay.h>
// Declare your global variables here

void main(void)
{
PORTD=0x00; //Выставляем все выходы порта D на 0, то есть, выключаем весь порт D
DDRD=0xFF; //Делаем порт D, как выход, чтобы на выходах порта было напряжение 5В
{
unsigned char migalka[] =   { 0b00000001, 0b00000011, 0b00000111, 0b00001111 // Инициализируем массив "migalka"
                            , 0b00011111, 0b00111111, 0b01111111, 0b11111111
                            , 0b11111110, 0b11111100, 0b11111000, 0b11110000
                            , 0b11100000, 0b11000000, 0b10000000, 0b00000000
                            , 0b00011000, 0b00111100, 0b01100110, 0b11000011
                            , 0b10000001, 0b00000000, 0b10000001, 0b11000011
                            , 0b11100111, 0b11111111, 0b10101010, 0b01010101
                            , 0b10101010, 0b01010101, 0b10101010, 0b00000000
                            , 0b11111111, 0b00000000, 0b11111111, 0b00000000
                            , 0b11111111, 0b00000000, 0b11111111, 0b00000000
                            , 0b11000000, 0b01100000, 0b00110000, 0b00011000
                            , 0b00001100, 0b00000110, 0b00000011, 0b00000101
                            , 0b00001001, 0b00010001, 0b00100001, 0b01000001
                            , 0b10000001, 0b01000010, 0b00100100, 0b00011000
                            , 0b00111100, 0b01111110, 0b11111111, 0b11100111
                            , 0b11000011, 0b10000001, 0b10011001, 0b10100101
                            , 0b11000011, 0b11011011, 0b11100111, 0b11111111
                            , 0b01111110, 0b10111101, 0b00111100, 0b01011010
                            , 0b10011001, 0b00011000, 0b00100100, 0b01000010
                            , 0b10000001, 0b00000000, 0b10000000, 0b11000000
                            , 0b11100000, 0b11110000, 0b11111000, 0b11111100
                            , 0b11111110, 0b11111111, 0b01111111, 0b00111111
                            , 0b00011111, 0b00001111, 0b00000111, 0b00000011
                            , 0b00000001, 0b00000000, 0b11111111, 0b10101010
                            , 0b11111111, 0b01010101, 0b11111111, 0b10101010
                            , 0b11111111, 0b10101010, 0b11111111, 0b01010101
                            , 0b00000001, 0b00000010, 0b00000100, 0b00001000
                            , 0b00010000, 0b00100000, 0b01000000, 0b10000001
                            , 0b10000010, 0b10000100, 0b10001000, 0b10010000
                            , 0b10100000, 0b11000001, 0b11000010, 0b11000100
                            , 0b11001000, 0b11010000, 0b11100001, 0b11100010
                            , 0b11100100, 0b11101000, 0b11110001, 0b11110010
                            , 0b11110100, 0b11111000, 0b11111001, 0b11111010
                            , 0b11111101, 0b11111111, 0b11101001, 0b11010010
                            , 0b10100100, 0b10010001, 0b10000100, 0b00100001
                            , 0b00001000, 0b00000010, 0b00000000};
unsigned char i = 0;
while(1) // Выполняется цикл
    {
    for (i=0; i<143; i++) // Выполняем 143 позиции массива.
    {
        PORTD = migalka[i]; // Общая задержка.
        delay_ms (60);
    }
    }
    }
    };

Можно сделать так, чтобы выполнение программы программа остановилось в определённом месте и ждало сигнала на одном из входов.
Кстати, выходы обозначаются как PORT, а входы как PIN
Для этого программу можно записать в таком виде:

PORTD.0=1; // Сигнал на выводе 0 порта D
while (!PINB.0); // Ждём сигнала на входе 0 порта B
PORTD.0=0; // Выключаем сигнал на выходе 0 порта D

Вот так выгдядит программа для управления прессом в линии сращивания деревянных брусков:

#include <mega8.h>
#include <delay.h>

// Declare your global variables here
// PORTD.0 - Упор
// PORTD.1 - Подача доски
// PORTD.2 - Пила
// PORTD.3 - Направляющая
// PORTD.4 - Толкатель
// PORTD.5 - Боковой пресс
// PORTD.6 - Верхний пресс
// PORTD.7 - Торцевой пресс
// PINB.1 - Концевик на приёмке заготовки
// PINB.2 - Концевик на торцевом прессе
// PINB.3 - Концевик на направляющей (верхнее положение)
// PINB.4 - Концевик верхнего положения упора

void main(void)
{
int i; // описание переменной "і" как целое число Int - (Integer)
while (1)
    {
    PORTD.0=1; // Упор поднимается
    PORTD.1=1; // Подача доски
    while (!PINB.1); // Доска на месте
    delay_ms (150);
    PORTD.1=0; // Подача выключается
    delay_ms(700); // Задержка 0,7 сек
    PORTD.2=1; // Подача пилы
    delay_ms(3000); // Задержка 3 сек
    PORTD.2=0; // Пила выключается и опускается
    delay_ms (700); // Задержка 0,7 сек
    PORTD.3=1; // Направляющая поднимается
    while (!PINB.3 || !PINB.4) // Если упор и направляющая подняты...
    PORTD.4=1; // Толкатель толкает доску под пресс
    delay_ms (1000); // Задержка
    PORTD.4=0; // Толкатель отходит
    delay_ms (1000); // Задержка
    PORTD.5=1; // Боковой пресс прижимает доску к упору
    delay_ms (300); // Задержка
    PORTD.6=1; // Верхний пресс прижимает доску
    delay_ms (700); // Задержка
    PORTD.7=1; // Давит торцевой гидравлический пресс
    delay_ms (3000); // Задержка
    for (i = 0; i<15 ; i++) // Работает верхний пресс
    {
    PORTD.6=1; // Прижим
    delay_ms(700); // Задержка
    PORTD.6=0; // Ослабление
    delay_ms(170); // Задержка
    PORTD.6=1; // Прижим
    }
    PORTD.7=0; // Торцевой пресс отходит
    while (!PINB.2);
    PORTD.5=0; // Боковой пресс отходит
    PORTD.6=0; // Верхний пресс поднимается
    delay_ms (1000); // Задержка
    PORTD.0=0; // Упор опускается
    delay_ms (1000); // Задержка
    PORTD.5=1; // Боковой пресс выталкивает доску в накопитель
    delay_ms (500); // Задержка
    PORTD.5=0; // Боковой пресс отходит
    PORTD.3=0; // Направляющая опускается
    delay_ms (1000); // Задержка
    // На начало программы
    }
    };

Следует уделить внимание вот этой строчке:

while (!PINB.3 || !PINB.4) // Если упор и направляющая подняты...

Для того, чтобы сработало, когда сигнал появится на PINB.3 И PINB.4 используем условный оператор ИЛИ потому, что программа не выполняется до тех пор, пока на PINB.3 ИЛИ
PINB.4 будет логический 0. Тоесть для того, чтобы программа выполнялась дальше, надо чтобы небыло 0 на обоих входах (тоесть стобя на обоих входах была логическая 1).

4

К МК можно подключить LCD.
Для этого в CodeVisionAVR при создании нового проекта следует указать к какому порту подключен LCD (во вкладке "LCD"), затем там-же нужно указать, сколько символов содержится в строке.
Теперь на LCD можно вывести какие-то данные.
Пишем:

{
lcd_gotoxy(2,0); // Задаём, с какого символа и в какой строке выводится надпись (номер символа, номер строки). Отсчёт идёт с нуля.

lcd_putsf("Текст"); // С третьего символа первой строки выводим слово Текст

lcd_gotoxy(1,1); // Задаём номер символа и номер строки

lcd_putsf("Текст 2"); // Со второго символа второй строки выводим надпись Текст 2
}

Можно сделать несколько сменяющих друг друга надписей. Для этого надо очистить LCD командой lcd_clear ()

{
lcd_gotoxy(2,0); // Задаём, с какого символа и в какой строке выводится надпись.

lcd_putsf("Текст"); // С третьего символа первой строки выводим слово Текст

lcd_gotoxy(1,1); // Задаём номер символа и номер строки

lcd_putsf("Текст 2"); // Со второго символа второй строки выводим надпись Текст 2

delay_ms (3000); // Ждём 3 секунды

lcd_clear(); // Очищаем дисплей и выводим следующие надписи

lcd_gotoxy(1,0); // Задаём, с какого символа и в какой строке выводится надпись.

lcd_putsf("Текст 3"); // Со второго символа первой строки выводим слово Текст 3

lcd_gotoxy(1,1); // Задаём номер символа и номер строки

lcd_putsf("Текст  4"); // Со второго символа второй строки выводим надпись Текст 4
}

5

Вот это я пытался время отсчитывать и выводить результат на LCD :)

void main(void)
{
char s, m, c; // Назначаем переменные
s=0; // Секунды
m=00; // Минуты
c=0; // Часы
lcd_init(8); // Инициализация дисплея на 8 символов в строке.

// Global enable interrupts
//#asm("sei")
lcd_putsf("Clock By\nSeregaT"); // При включении выводится на дисплей: 1я строчка - Clock By, 2я строчка - SeregaT :)
delay_ms (2000); // Задержка 2 секунды
lcd_clear(); // Очистка дисплея

while (1) //Бесконечный цикл
{
for (m = 0; m<60; m++) // Цикл, отсчитывающий минуты (60 циклов - 1 час).
{
for (s = 0; s<60; s++) // Цикл, отсчитывающий секунды (60 циклов - 1 минута).
{
lcd_clear(); // Очищаем дисплей.
sprintf(lcd_buffer, "%d:%d:%d\nATmega16", c, m, s); // Заносим в буфер LCD переменные в таком виде: часы:минуты:секунды и на следующей строчке надпись ATmega16
lcd_puts(lcd_buffer); // Выводим на дисплей содержимое LCD буффера.
delay_ms (1000); // Задержка 1 секунда
      }
}
c=c+1; // Отсчитываем часы (чтобы поменялось значение, нужно чтобы прошло 60 минутных циклов).
}
} // Возвращаемся на начало цикла while (1)

6

Защита от помех
Различные помехи могут вызывать ложные срабатывания различных кнопок и т.д. То, что дома на столе работает отлично, в реальных условиях на промышленном оборудовании результаты могут быть самыми непредсказуемыми. Чтобы этого не произошло, обязательно надо делать программную защиту от помех. Для этого после команды, которая ожидает нажатие кнопки нужно сделать небольшую задержку и снова проверить нажатие этой кнопки.
Вот фрагмент кода с подобной защитой:

if (!PIND.0) // Если нажата кнопка на PORTD.0
{
delay_ms (1); // делаем задержку 1 миллисекунду
if (!PIND.0) // И снова проверяем нажатие кнопки, после чего выполняется назначенная этой кнопке операция
{
PORTB.0=1; // Выводится сигнал на PORTB.0
}
}

7

Когда будет продолжение можно ли через icq с вами связаться? Можно ли на примере какой нибудь программы(устройства) обьяснить её работу здесь?

Отредактировано Борис (2009-06-13 03:37:00)

8

Можно и по ICQ
274284575
Тока я редко аську включаю. Ну пример могу выложить. Вот текст программы для регулировки времени провара в аппарате контактной сварки. Написана для CVAVR

// PIND.0 - Увеличение переменной
// PIND.1 - Уменьшение переменной
// PIND.2 - Кнопка выбора меню настройки
// PIND.3 - Кнопка включения непрерывного режима
// PIND.4 - Педаль
// PORTB.0 - Включение пневмоклапана прижимного устройства.
// PORTB.1 - Включение трансформатора
#include <mega16.h>
#include <delay.h>
#include <stdio.h>
char lcd_buffer[33];
// Alphanumeric LCD Module functions
#asm
   .equ __lcd_port=0x1B ;PORTA
#endasm
#include <lcd.h>
eeprom unsigned int c; //Объявление переменной для записи в eeprom
eeprom unsigned int d; // Объявление переменной для записи в eeprom
unsigned int a; //Прижим (время прижима до включения сварки)
unsigned int b; //Сварка (время включения трансформатора)
//eeprom unsigned int c; //Автомат (включения непрерывного режима)
// Declare your global variables here
void main(void)
{
a=c; //Присваиваем основной переменной значение переменной, записанной в eeprom
b=d; //Присваиваем основной переменной значение переменной, записанной в eeprom
// LCD module initialization
lcd_init(8);

start:     while (!PIND.3); // Ждём, когда кнопка включения автоматического режима будет отпущена, чтобы включить стартовое меню при котором можно начинать работу
           lcd_clear(); // Очищаем дисплей.
           lcd_putsf("PyАЅo№\npe¶ёј"); // Меню автоматического режима (Выводится надпись: Авто режим)   
start1:      while (1)
      {
      if (!PIND.3) // Если нажата кнопка включения непрерывного режима, переходим в соответствующий цикл
      {
      delay_ms (5);
      if (!PIND.3)
      {
      goto lcd4;
      }
      }
      if (!PIND.0) // Если нажата кнопку увеличения переменной...
      {
      delay_ms (5);
      if (!PIND.0) // Антидребезг
      {
      goto lcd2; // Переходим в меню настройки времени включения трансформатора
      }
      }
      if (!PIND.1) // Если нажата кнопка уменьшения переменной...
      {
      delay_ms (5);
      if (!PIND.1) // Антидребезг
      {
      goto lcd2; // Переходим в меню настройки времени включения трансформатора
      }
      }

      if (!PIND.4) // Если нажата педаль, выполняется процедура контактной сварки
      {
      delay_ms (5);
      if (!PIND.4) // Антидребезг
      {
      while (1)
      {
      PORTB.0=1; // Включается прижимное устройство
      PORTB.1=1; // Включается сварочный трансформатор
      if (PIND.4)
      {
      delay_ms (1);
      if (PIND.4)
      {
      PORTB.1=0; // Выключается сварочный трансформатор
      PORTB.0=0; // Выключается прижимное устройство
      goto start1;
      }
      }
      }
      }
      }
      if (!PIND.2) // Если нажата кнопка "Выбор", переходим на установку задержки прижима
      {
      delay_ms (5);
      if (!PIND.2) // Антидребезг
      {
      goto test2; // Безусловный переход на метку test
      }
      }
      }
test: while (!PIND.2); // Ждём, когда кнопка "Выбор" будет отпущена
      goto lcd; // Безусловный переход на метку lcd
      while (1) // Меню задержки прижима
      {
use:  if (!PIND.4) // Если нажата педаль, переходим в рабочий режим
      {
      delay_ms (5);
      if (!PIND.4) // Антидребезг
      {
      c=a; //Переменной eeprom присваиваем значение обычной переменной для сохранения в памяти.
      goto lcd4; // Переход на метку start (в начало программы)
      }
      }
      if (!PIND.3) // Если нажата кнопка непрерывного режима, переходим в соответствующий режим
      {
      delay_ms (5);
      if (!PIND.3) // Антидребезг
      {
      c=a; //Переменной eeprom присваиваем значение обычной переменной для сохранения в памяти.
      goto automat; // Переход на метку auto
      }
      }     
      if (!PIND.2) // Если нажата кнопка "Выбор", переходим на установку задержки прижима
      {
      delay_ms (5);
      if (!PIND.2) // Антидребезг
      {
      c=a; //Переменной eeprom присваиваем значение обычной переменной для сохранения в памяти.
      goto test2; // Переход на метку test2
      }
      }
      if (!PIND.0) // Если нажата кнопка увеличения переменной, увеличиваем переменную a на 1.
      {
      delay_ms (5);
      if (!PIND.0) // Антидребезг
      {
      delay_ms (70);
      a=a+1;
      if (a>1000) // Если a больше 1000, устанавливает значение a равное 1000
      {
      a=1000; // a не может быть больше 1000
      };
      //while (!PIND.0);     
      goto lcd; // Переход на метку lcd
      }
      }     
      if (!PIND.1) // Если нажата кнопка уменьшения переменной, уменьшаем значение a на 1
      {
      delay_ms (5);
      if (!PIND.1) // Антидребезг
      {
      delay_ms (70);
      a=a-1;
      if (a<50)
      {
      a=50; // а не может быть меньше 50
      };
      goto lcd;     
      };
      }
      }
test2: while (!PIND.2); // Ждём, когда кнопка выбора будет отпущена
      goto lcd2; // Переход на меткку lcd2
      while (1) //Меню задержки сварки
      {
use2: if (!PIND.4) // Если нажата педаль, переходим в авоматический режим
      {
      delay_ms (5);
      if (PIND.4) // Антидребезг
      {
      d=b; //Переменной eeprom присваиваем значение обычной переменной для сохранения в памяти.
      goto lcd4;
      }
      }
      if (!PIND.3) // Если нажата кнопка непрерывного режима, переходим в соответствующий режим
      {
      delay_ms (5);
      if (!PIND.3) // Антидребезг
      {
      d=b; //Переменной eeprom присваиваем значение обычной переменной для сохранения в памяти.
      goto automat; // Переход на метку auto
      }
      }     
      if (!PIND.2) // Если нажата кнопка "Выбор", переходим на установку задержки включения трансформатора
      {
      delay_ms (5);
      if (!PIND.2) // Антидребезг
      {
      d=b; //Переменной eeprom присваиваем значение обычной переменной для сохранения в памяти.
      goto test; // Переход на метку test3
      }
      }
      if (!PIND.0) // Увеличение переменной b (время включения трансформатора)
      {
      delay_ms (5);
      if (!PIND.0) // Антидребезг
      {
      delay_ms (70);
      b=b+1;
      if (b>1000)
      {
      b=1000; // b не может быть больше 2500
      };   
      goto lcd2; // Переход на метку lcd2
      }
      }     
      if (!PIND.1) // Уменьшение переменной b
      {
      delay_ms (5);
      if (!PIND.1) // Антидребезг
      {
      delay_ms (70);
      b=b-1;
      if (b<10)
      {
      b=10; // b не может быть меньше 10
      };
      goto lcd2; // Переход на метку lcd2     
      };
      }
      }

automat: while (1) // цикл непрерывного режим
      {
      if (!PIND.0)
      {
      delay_ms (1);
      if (!PIND.0)
      {
      goto lcd2;
      }
      }
      if (!PIND.1)
      {
      delay_ms (1);
      if (!PIND.1)
      {
      goto lcd2;
      }
      }
      if (!PIND.2) // Если нажата кнопка "Выбор", переходим на установку задержки прижима
      {
      delay_ms (1);
      if (!PIND.2) // Антидребезг
      {
      goto test2; // Безусловный переход на метку test
      }
      }           
      if (!PIND.3) // Если нажата кнопка включения-отключения непрерывного режима, переходим в основной (рабочий) режим
      {
      delay_ms (1);
      if (!PIND.3) // Антидребезг
      {
      while (!PIND.3); // Ждём, когда кнопка будет отпущена     
      goto start; // Переход на метку start
      }
      }     
      if (!PIND.4) // Если нажата педаль, выполняется непрерывный режим
      {
      delay_ms (1);
      if (!PIND.4) // Антидребезг
      {
      PORTB.0=1;
      delay_ms (a);
      PORTB.1=1;
      delay_ms (b);
      PORTB.1=0;
      PORTB.0=0;
      delay_ms (2);
      if (!PIND.4)
      {
      delay_ms (1);
      if (!PIND.4)
      {
      while (1)
      {
      delay_ms (2);
      if (PIND.4)
      {
      goto automat;
      }
      }
      }
      //delay_ms (c);     
      }
      }
      }
      }         
lcd:       lcd_clear(); // Очищаем дисплей.
           sprintf(lcd_buffer, "Ёpё¶ёј\n%d ms", a); // Меню прижима (выводится надпись: Прижим (a) ms)
           lcd_puts(lcd_buffer);
           goto use; // Безусловный переход на метку use
           
lcd2:      lcd_clear(); // Очищаем дисплей.
           sprintf(lcd_buffer, "Cіapєa\n%d ms", b); // Меню сварки (выводится надпись: Сварка (b) ms)
           lcd_puts(lcd_buffer);
           goto use2; // Переход на метку use2
           
           
lcd4:      lcd_clear(); // Очищаем дисплей.
           sprintf(lcd_buffer, "Aіїo\n%d ms", b); // Меню сварки
           lcd_puts(lcd_buffer);
           while (!PIND.3);
           goto automat;         
           };

Эта программа полностью работоспособна и работает на промышленном оборудовании в условиях очень жёстких помех.
Подробнее работу этой программы я опишу чуть позже (сейчас некогда).

9

Вот, начнём разбор данной программы.

Тут задействована еще одна фишка, которая не была рассмотрена ранее. Это сохранение настроек в памяти eeprom.
Чтобы переменная записалась в эту память, её следует объявить как eeprom
Пример: eeprom unsigned int i; //(i - имя переменной, может быть любым)
В этом случае любое изменение переменной записывается в эту память. Но количество циклов перезаписи памяти eeprom ограничено, поэтому в случае частого изменения переменной лучше поступить следующим образом:
Назначаем две переменных, одна из которых будет объявлена как eeprom, а другая как обычная переменная. При запуске программы, присваиваем обычной переменной значение переменной eeprom. Все изменения будем производить с обычной переменной, а после того, как значение обычной переменной достигло нужного нам значения (в моём случае при выходе из меню настройки), то присваиваем это значение переменной, которая объявлена как eeprom. Всё, переменная сохранена в памяти и при запуске программы её значение будет присвоено обычной переменной, с которой и работает программа. Тогда получится что когда увеличиваем переменную прибавляя к её значению 1 например с 1 до 100 а потом присваиваем полученое значение переменной eeprom, то память будет перезаписана не 100 раз, а всего 1 раз.
Вот фрагмент кода с подобным объявлением переменной:

eeprom unsigned int c;
eeprom unsigned int d;
unsigned int a; //Прижим (время прижима до включения сварки)
unsigned int b; //Сварка (время включения трансформатора)

10

а какие еще библиотеки используются типа <delay.h>


Вы здесь » XLAN » Микроконтроллеры AVR » Программирование AVR