Немножко на мой взгляд улутшил код. Теперь при входе в режим КАЛИБРОВКИ, в зависимости от режима меню - мигает тот светодиод - который ми калибруем или оба.
До этого было не понятно в каком режиме мы находимся.
//********** (РЕЖИМ 1-ШАГ) Крутим с помощью сдвига --рабочая - крутит туда сюда без потери шагов - ускоряет - отключает катушки после бездействия
//PORTB - 8, 9, 10, 11 - Шаговик. && 12-кнопка Menu \ 13-Светодиод 1й штор.
//PORTD - 4, 5, 6, 7 - Шаговик. && 2-кнопка UP \ 3-кнопка DOWN
// А0-Светодиод 2й штор..
#include <CyberLib.h>
//Задаем ускорение
#define uskor 3
byte n1 = 1;// Сдвигаем 1 бит
byte n3 = 0x10;
byte f_tim = 0;
byte sped_Xt = uskor;//Начальная скорость
byte sped_X = 0; //Ускорение
byte sped_Zt = uskor;//Начальная скорость
byte sped_Z = 0; //Ускорение
bool f_run1X = 0;//Сброс после остановки 3 переменные.
bool f_run2X = 0;
unsigned long no_runX; //Переменная для прошедшего периода
bool f_run1Z = 0;//Сброс после остановки 3 переменные.
bool f_run2Z = 0;
unsigned long no_runZ; //Переменная для прошедшего периода
// Переменные для кн.Menu
bool kn_menu;
bool f_menu;
bool f_Mpush;
bool f_Md;
uint8_t Menu = 1;
uint8_t temp_Menu;
bool kalib;
unsigned long menu_dreb;
unsigned long menu_klik;
// Переменные для кн.Up
bool kn_Up;
bool f_Up;
bool state_Up;
bool _UP;
uint32_t Up_dreb;
// Переменные для кн.Down
bool kn_Down;
bool f_Down;
bool state_Down;
bool _Down;
uint32_t Down_dreb;
uint32_t sbros;
bool f_sbros;
uint32_t cur_time;
uint32_t blink_time;
bool f_blink;
int Shtora1 = 50;// количество шагов для полного закрытия шторы 1;
int Shtora2 = 34;// количество шагов для полного закрытия шторы 2
void setup() {
// DDRB пин, 8,9,10,11 - Шаговик, pin 12- вход, 13- Выход
DDRB = DDRB | B00101111;
// pin 8,9,10,11,13 - выход в 0 а входы pin 12, - 0
PORTB = B00000000;
// DDRD, подключенный к двигателю pin 4,5,6,7 как выход,pin2,3 Выход
DDRD = DDRD | B11110000;
// pin 4,5,6,7 - выход в 0 а входы pin 2,3 - 0
PORTD = B00000000;//;
D14_Out; // Led_2
D14_Low;
Serial.begin(9600);
// Инициализировать TIMER1
noInterrupts (); // отключить все прерывания
TCCR1A = 0;
TCCR1B = 0;
TCNT1 = 0;
OCR1A = 125; // сравнить регистр (скорость!!!(2ms=125 - если медленнее - УВЕЛИЧИВАЕМ)
TCCR1B |= (1 << WGM12); // Режим СТС
TCCR1B |= (1 << CS12); // 256 делитель
TIMSK1 |= (1 << OCIE1A ); // включить таймер сравнить прерываний
interrupts(); // включить все прерывания
}
ISR (TIMER1_COMPA_vect) // Функция прерывания таймера
{
// Serial.println(f_tim);
f_tim = B1111;
}
//Функция вращения dvigatel 1
void RunX (bool perem_X)
{
f_tim &= B1110;
if (perem_X) {
n1 = (n1 >> 1) | (n1 << 3); //Сдвигаем
--Shtora1;
}
else {
n1 = (n1 << 1) | (n1 >> 3); //Сдвигаем
++Shtora1;
}
n1 = 0x0F & n1; //Маскируем кнопки
PORTB = (PORTB & 0xF0) | n1; //Очищаем Младшие биты и пишем туда n1
}
//Функция dvigatel 3
void RunZ (bool perem_Z)
{
f_tim &= B1011;
if (perem_Z) {
n3 = (n3 >> 1) | (n3 << 3); //Сдвигаем
--Shtora2;
}
else {
n3 = (n3 << 1) | (n3 >> 3); //Сдвигаем
++Shtora2;
}
n3 = 0xF0 & n3;//Маскируем
PORTD = (PORTD & 0xF) | n3; //Очищаем старшие биты и пишем туда n3
//Serial.println(n3);
}
void loop() {
static bool tem_UP;
if (_UP != tem_UP) {
tem_UP = _UP;
Serial.print("UP- "); Serial.println(_UP);
}
static bool tem_Down;
if (_Down != tem_Down)
{
tem_Down = _Down;
Serial.print("Down- "); Serial.println(_Down);
}
cur_time = millis();
///////////////////Проверка кнопки МЕНЮ - АНТИДРЕБЕЗГ
if (D12_Read && !f_menu)
{
menu_dreb = cur_time;
f_menu = 1;
}
if (!D12_Read)
{
kn_menu = 0;
f_menu = 0;
}
if (f_menu && cur_time - menu_dreb >= 20)
{
kn_menu = 1;
if (!f_Mpush) {
menu_klik = cur_time;
f_Mpush = 1;
}
}
if (f_Mpush && !kn_menu && cur_time - menu_klik < 500) {
if (_UP || _Down) {
_UP = 0;
_Down = 0;
}
else Menu++; // Меняем
if (Menu > 3) Menu = 1;
f_Mpush = 0;
}
else if (f_Mpush && !kn_menu && cur_time - menu_klik > 500) {
kalib = !kalib; // Включаем калибровку
Serial.print("kalib- "); Serial.println(kalib);
f_Mpush = 0;
}
///////////////////////Проверка кнопки UP - АНТИДРЕБЕЗГ
if (D2_Read != f_Up) { //Если сигнал изменился
f_Up = !f_Up;
Up_dreb = cur_time;
}
if (kn_Up == D2_Read && cur_time - Up_dreb > 20) kn_Up = !D2_Read;
// Было нажатие
if (kn_Up && !state_Up) {
if (_UP || _Down) {
_UP = 0;
_Down = 0;
state_Up = 1;
}
else {
_UP = !_UP; // Меняем значение
state_Up = 1;
}
}
if (!kn_Up)state_Up = 0; // Отпустили
///////////////////////Проверка кнопки DOWN - АНТИДРЕБЕЗГ
if (D3_Read != f_Down) { //Если сигнал изменился
f_Down = !f_Down;
Down_dreb = cur_time;
}
if (kn_Down == D3_Read && cur_time - Down_dreb > 20) kn_Down = !D3_Read;
// Было нажатие
if (kn_Down && !state_Down) {
if (_UP || _Down) {
_UP = 0;
_Down = 0;
state_Down = 1;
}
else {
_Down = !_Down; // Меняем значение
state_Down = 1;
}
}
if (!kn_Down)state_Down = 0; // Отпустили
//////////////////////// С кнопками закончили продолжаем логику
if (!kalib)
{
if (Menu != temp_Menu) {
temp_Menu = Menu;
Serial.print("Menu- "); Serial.println(Menu);
switch (Menu) {
case 1: D13_High; D14_Low; break;
case 2: D13_Low; D14_High; break;
case 3: D13_High; D14_High; break;
}
}
}
else {
if (cur_time - blink_time >= 300)
{
blink_time = cur_time;
switch (Menu) {
case 1: D13_Inv; D14_Low; break;
case 2: D13_Low; D14_Inv; break;
case 3: D13_Inv; D14_Inv; break;
}
}
}
/////////////////////////// Запуск 1го двигателя если " perem_X != 0 "
//if (!kalib) {
if (_UP || _Down) {
if (Menu != 2) {
if (f_tim & (1 << 0)) {
if (!sped_X) {
if (!kalib)//Калибровка отк.
{
if (_UP && Shtora1 < 50) {//3592
RunX(0);
Serial.print("Shtora1- "); Serial.println(Shtora1);
}
if (_Down && Shtora1 > 0) {
RunX(1);
Serial.print("Shtora1- "); Serial.println(Shtora1);
}
}
else { //Калибровка вкл.
if (_UP) {
Shtora1 = 0;
RunX(0);
Serial.print("Shtora1- "); Serial.println(Shtora1);
}
if (_Down) {
Shtora1 = 1;
RunX(1);
Serial.print("Shtora1- "); Serial.println(Shtora1);
}
}
if (sped_Xt > 0) {
--sped_Xt;
sped_X = sped_Xt;
}
}
else {
--sped_X;
f_tim &= B1110;
}
}////
else {
f_run2X = 1;
no_runX = cur_time;
}
}
}
else {
sped_Xt = uskor;
sped_X = 0; // для пропуска 1го тика
}
//}
/////////////////Запуск 3го двигателя если " perem_Z != 0 "
//if (!kalib) {
if (_UP || _Down) {
if (Menu != 1) {
if (f_tim & (1 << 2)) {
if (!sped_Z) {
if (!kalib)//Калибровка отк.
{
if (_UP && Shtora2 < 34) {//3475
RunZ(0);
Serial.print("Shtora2- "); Serial.println(Shtora2);
}
if (_Down && Shtora2 > 0) {
RunZ(1);
Serial.print("Shtora2- "); Serial.println(Shtora2);
}
}
else {//Калибровка Вкл.
if (_UP) {
Shtora2 = 0;
RunZ(0);
Serial.print("Shtora2- "); Serial.println(Shtora2);
}
if (_Down) {
Shtora2 = 1;
RunZ(1);
Serial.print("Shtora2- "); Serial.println(Shtora2);
}
}
if (sped_Zt > 0) {
--sped_Zt;
sped_Z = sped_Zt;
}
}
else {
--sped_Z;
f_tim &= B1011;
}
}////
else {
f_run2Z = 1;
no_runZ = cur_time;
}
}
}
else {
sped_Zt = uskor;
sped_Z = 0; // для пропуска 1го тика
}
//Если достигли конца сбрасываем UP\Down
if (f_tim != 15)
{
sbros = cur_time;
f_sbros = 0;
}
if (!f_sbros && cur_time - sbros > 1500)
{
f_sbros = 1;
_UP = 0;
_Down = 0;
}
//Снимаем напряжение с катушек двигателя X
if (f_run2X && cur_time - no_runX >= 1000)// закончилось ли время
{
f_run2X = 0;
PORTB &= 0xF0;
}
//Снимаем напряжение с катушек двигателя Z
if (f_run2Z && cur_time - no_runZ >= 1000)// закончилось ли время
{
f_run2Z = 0;
PORTD &= 0xF;
}
}
Немножко на мой взгляд улутшил код. Теперь при входе в режим КАЛИБРОВКИ, в зависимости от режима меню - мигает тот светодиод - который ми калибруем или оба.
До этого было не понятно в каком режиме мы находимся.
А оба зачем? Две шторы одновременно смысла нет калибровать. У нас самое главное не работает.....моторы не крутятся и кренка сильно греется!!! В симуляторе светодиоды бегают прикольно, а реальная сборка работать не хочет. Первый скетч работает изумительно, для режима калибровки самое то....пока держишь кнопку - мотор крутится, отпустил - остановился. Вот этот скетч.
//********** (РЕЖИМ 1-ШАГ) Крутим с помощью сдвига --рабочая - крутит туда сюда без потери шагов - ускоряет - отключает катушки после бездействия
//PORTB - 8, 9, 10, 11 - Шаговик. && 12, 13 - Вход сигнал от 2х кнопок (влево - вправо)
//PORTD - 4, 5, 6, 7 - Шаговик. && 2, 3 - остаются для переферии
#define uskor 2 //Задаем ускорение
byte n1 = 1;// Сдвигаем 1 бит
byte n3 = 0x10;
byte f_tim = 0;
long int perem_X = 0;
long int perem_Z = 0;
byte sped_Xt = uskor;//Начальная скорость
byte sped_X = 0; //Ускорение
byte sped_Zt = uskor;//Начальная скорость
byte sped_Z = 0; //Ускорение
bool f_run1X = 0;//Сброс после остановки 3 переменные.
bool f_run2X = 0;
unsigned long no_runX; //Переменная для прошедшего периода
bool f_run1Z = 0;//Сброс после остановки 3 переменные.
bool f_run2Z = 0;
unsigned long no_runZ; //Переменная для прошедшего периода
void setup() {
// пин, 8, 9, 10, 11 - Шаговик, 2, 3- переферия
DDRB = 0xCF;
//Устанавлюем значение выходов в 0 а входы - подтягивающий резистор
PORTB = 0x30;
// PORTD, подключенный к двигателю 3 как выход, Две кнопки с подтяжкой pin2-3
DDRD = DDRD | B11110000;
//Устанавлюем значение выходов PORTD в 0
PORTD = PORTD | B00001100;//x0F;
// Serial.begin(9600);
// Инициализировать TIMER1
noInterrupts (); // отключить все прерывания
TCCR1A = 0;
TCCR1B = 0;
TCNT1 = 0;
OCR1A = 125; // сравнить регистр (скорость!!!(2ms=125 - если медлиннее - УВЕЛИЧУЕМ)
TCCR1B |= (1 << WGM12); // Режим СТС
TCCR1B |= (1 << CS12); // 256 делитель
TIMSK1 |= (1 << OCIE1A ); // включить таймер сравнить прерываний
interrupts(); // включить все прерывания
}
ISR (TIMER1_COMPA_vect) // Функция прерывания таймера
{
// Serial.println(f_tim);
f_tim = B1111;
}
//Функция вращения dvigatel 1
void RunX ()
{
f_tim &= B1110;
if (perem_X > 0) {
n1 = (n1 >> 1) | (n1 << 3); //Сдвигаем
--perem_X;
}
else {
n1 = (n1 << 1) | (n1 >> 3); //Сдвигаем
++perem_X;
}
n1 = 0x0F & n1; //Маскируем кнопки
PORTB = (PORTB & 0xF0) | n1; //Очищаем Младшие биты и пишем туда n1
}
//Функция dvigatel 3
void RunZ ()
{
f_tim &= B1011;
if (perem_Z > 0) {
n3 = (n3 >> 1) | (n3 << 3); //Сдвигаем
--perem_Z;
}
else {
n3 = (n3 << 1) | (n3 >> 3); //Сдвигаем
++perem_Z;
}
n3 = 0xF0 & n3;//Маскируем
PORTD = (PORTD & 0xF) | n3; //Очищаем старшие биты и пишем туда n3
//Serial.println(n3);
}
void loop() {
//Кнопки 1 и 2 служат для демонстрации работы. Считается замкнутой при подаче МИНУСА
if ((PIND & (1 << 3))) //проверяем кнопку 1 - нажали? Можно использовать if(!digitalRead(2))
{
//Задаем количество шагов для дв.- ВПРАВО "perem_X = Количеству шагов;"
perem_X = 10;
perem_Z = -10;
}
//else perem_X = 0; // ВНИМАНИЕ если задаём количество шагов - эту строчку удаляем!!!
if ((PIND & (1 << 2))) //проверяем кнопку 2 - нажали? Можно использовать if(!digitalRead(3))
{
//Задаем количество шагов для дв.- ВЛЕВО "perem_X = -Количеству шагов;"
perem_X = -10;
perem_Z = 10;
}
/////////////////////////// Запуск 1го двигателя если " perem_X != 0 "
if (perem_X != 0) {
f_run1X = 1;
f_run2X = 0;
if (f_tim & (1 << 0)) {
if (!sped_X) {
RunX();
if (sped_Xt > 0) {
--sped_Xt;
sped_X = sped_Xt;
}
}
else {
--sped_X;
f_tim &= B1110;
}
}
}
else {
sped_Xt = uskor;
sped_X = 0; // для пропуска 1го тика
}
/////////////////Запуск 3го двигателя если " perem_Z != 0 "
if (perem_Z != 0) {
f_run1Z = 1;
f_run2Z = 0;
if (f_tim & (1 << 2)) {
if (!sped_Z) {
RunZ();
if (sped_Zt > 0) {
--sped_Zt;
sped_Z = sped_Zt;
}
}
else {
--sped_Z;
f_tim &= B1011;
}
}
}
else {
sped_Zt = uskor;
sped_Z = 0; // для пропуска 1го тика
}
//Снимаеммаем напряжение с катушек двигателя X
if (f_run1X && perem_X == 0) //Служит для запуска отключения катушек
{
f_run1X = 0;
f_run2X = 1;
no_runX = millis();
}
if (f_run2X && millis() - no_runX >= 1000)// Проверяем закончилось ли время
{
f_run2X = 0;
//Снимаем напряжение с катушек
PORTB &= 0xF0;
}
//Снимаеммаем напряжение с катушек двигателя Z
if (f_run1Z && perem_Z == 0) //Служит для запуска отключения катушек
{
f_run1Z = 0;
f_run2Z = 1;
no_runZ = millis();
}
if (f_run2Z && millis() - no_runZ >= 1000)// Проверяем закончилось ли время
{
f_run2Z = 0;
//Снимаем напряжение с катушек
PORTD &= 0xF;
}
}
По-поводу калибровки я считаю, что правильней калибровать "0" вверху, т.е. начальное положение из которого штора разматывается и чтобы штора не замоталась в барабан.
Вот скетч провери его на живой ардуине, правда на однм двигателе, крутит отключает, ничего не греется. Проблему скорости давал Сериал, пришлось его удалить. В принцепе он нужен только для настройки. А так пока искал причину по скорости то таймер поменял и так помелочам. Ммаксимальную высоту будете ставить в самом начале _ там написано
//********** (РЕЖИМ 1-ШАГ) Крутим с помощью сдвига --рабочая - крутит туда сюда без потери шагов - ускоряет - отключает катушки после бездействия
//PORTB - 8, 9, 10, 11 - Шаговик. && 12-кнопка Menu \ 13-Светодиод 1й штор.
//PORTD - 4, 5, 6, 7 - Шаговик. && 2-кнопка UP \ 3-кнопка DOWN
// А0-Светодиод 2й штор..
#include <CyberLib.h>
#define uskor 5 //Задаем ускорение
//Здесь устанавливаем максимальное кол. шагов для штор
#define max_Sht1 5000
#define max_Sht2 5000
byte n1 = 1;// Сдвигаем 1 бит
byte n3 = 0x10;
bool f_timX = 0;
bool f_timZ = 0;
//long int perem_X = 0;
//long int perem_Z = 0;
byte sped_Xt = uskor;//Начальная скорость
byte sped_X = 0; //Ускорение
byte sped_Zt = uskor;//Начальная скорость
byte sped_Z = 0; //Ускорение
bool f_run1X = 0;//Сброс после остановки 2 переменные.
//bool f_run1X = 0;
unsigned long no_runX; //Переменная для прошедшего периода
bool f_run1Z = 0;//Сброс после остановки 2 переменные.
//bool f_run1Z = 0;
unsigned long no_runZ; //Переменная для прошедшего периода
// Переменные для кн.Menu
bool kn_menu;
bool f_menu;
bool f_Mpush;
bool f_Md;
uint8_t Menu = 1;
uint8_t temp_Menu;
bool kalib;
unsigned long menu_dreb;
unsigned long menu_klik;
// Переменные для кн.Up
bool kn_Up;
bool f_Up;
bool state_Up;
bool _UP;
uint32_t Up_dreb;
// Переменные для кн.Down
bool kn_Down;
bool f_Down;
bool state_Down;
bool _Down;
uint32_t Down_dreb;
//сбрасываем UP\Down
uint32_t sbros;
bool f_sbros;
uint32_t cur_time;//Миллис читаем один раз
uint32_t blink_time;//Мигаем в режиме калибровки
int Shtora1 = 50;// количество шагов для полного закрытия шторы 1;
int Shtora2 = 34;// количество шагов для полного закрытия шторы 2
void setup() {
// DDRB пин, 8,9,10,11 - Шаговик, pin 12- вход, 13- Выход
DDRB = DDRB | B00101111;
// pin 8,9,10,11,13 - выход в 0 а входы pin 12, - 0
PORTB = B00000000;
// DDRD, подключенный к двигателю pin 4,5,6,7 как выход,pin2,3 Выход
DDRD = DDRD | B11110000;
// pin 4,5,6,7 - выход в 0 а входы pin 2,3 - 0
PORTD = B00000000;//;
D14_Out; // Led_2
D14_Low;
//Serial.begin(9600);
// Инициализировать TIMER1
StartTimer1(Time_Closk, 2000);
}
void Time_Closk() // Функция прерывания таймера
{
f_timX = 1;
f_timZ = 1;
}
//Функция вращения dvigatel 1
void RunX (bool perem_X)
{
f_timX = 0;
if (perem_X) {
n1 = (n1 >> 1) | (n1 << 3); //Сдвигаем
--Shtora1;
}
else {
n1 = (n1 << 1) | (n1 >> 3); //Сдвигаем
++Shtora1;
}
n1 = 0x0F & n1; //Маскируем кнопки
PORTB = (PORTB & 0xF0) | n1; //Очищаем Младшие биты и пишем туда n1
}
//Функция dvigatel 3
void RunZ (bool perem_Z)
{
f_timZ = 0;
if (perem_Z) {
n3 = (n3 >> 1) | (n3 << 3); //Сдвигаем
--Shtora2;
}
else {
n3 = (n3 << 1) | (n3 >> 3); //Сдвигаем
++Shtora2;
}
n3 = 0xF0 & n3;//Маскируем
PORTD = (PORTD & 0xF) | n3; //Очищаем старшие биты и пишем туда n3
}
void loop() {
cur_time = millis();
///////////////////Проверка кнопки МЕНЮ - АНТИДРЕБЕЗГ
if (D12_Read && !f_menu)
{
menu_dreb = cur_time;
f_menu = 1;
}
if (!D12_Read)
{
kn_menu = 0;
f_menu = 0;
}
if (f_menu && cur_time - menu_dreb >= 20)
{
kn_menu = 1;
if (!f_Mpush) {
menu_klik = cur_time;
f_Mpush = 1;
}
}
if (f_Mpush && !kn_menu && cur_time - menu_klik < 500) {
if (_UP || _Down) {
_UP = 0;
_Down = 0;
}
else Menu++; // Меняем
if (Menu > 3) Menu = 1;
f_Mpush = 0;
}
else if (f_Mpush && !kn_menu && cur_time - menu_klik > 500) {
kalib = !kalib; // Включаем калибровку
f_Mpush = 0;
}
///////////////////////Проверка кнопки UP - АНТИДРЕБЕЗГ
if (D2_Read != f_Up) { //Если сигнал изменился
f_Up = !f_Up;
Up_dreb = cur_time;
}
if (kn_Up == D2_Read && cur_time - Up_dreb > 20) kn_Up = !D2_Read;
// Было нажатие
if (kn_Up && !state_Up) {
if (_UP || _Down) {
_UP = 0;
_Down = 0;
state_Up = 1;
}
else {
_UP = !_UP; // Меняем значение
state_Up = 1;
}
}
if (!kn_Up)state_Up = 0; // Отпустили
///////////////////////Проверка кнопки DOWN - АНТИДРЕБЕЗГ
if (D3_Read != f_Down) { //Если сигнал изменился
f_Down = !f_Down;
Down_dreb = cur_time;
}
if (kn_Down == D3_Read && cur_time - Down_dreb > 20) kn_Down = !D3_Read;
// Было нажатие
if (kn_Down && !state_Down) {
if (_UP || _Down) {
_UP = 0;
_Down = 0;
state_Down = 1;
}
else {
_Down = !_Down; // Меняем значение
state_Down = 1;
}
}
if (!kn_Down)state_Down = 0; // Отпустили
//////////////////////// С кнопками закончили продолжаем логику
if (!kalib)
{
if (Menu != temp_Menu) {
temp_Menu = Menu;
switch (Menu) {
case 1: D13_High; D14_Low; break;
case 2: D13_Low; D14_High; break;
case 3: D13_High; D14_High; break;
}
}
}
else {
if (cur_time - blink_time >= 300)
{
blink_time = cur_time;
switch (Menu) {
case 1: D13_Inv; D14_Low; break;
case 2: D13_Low; D14_Inv; break;
case 3: D13_Inv; D14_Inv; break;
}
}
}
/////////////////////////// Запуск 1го двигателя если " perem_X != 0 "
if (f_timX) {
if (_UP || _Down) {
if (Menu != 2) {
if (!sped_X) {
if (!kalib) { //Калибровка отк.
if (_UP && Shtora1 < max_Sht1) {//3592
RunX(0);
}
if (_Down && Shtora1 > 0) {
RunX(1);
}
}
else { //Калибровка вкл.
if (_UP) {
Shtora1 = 0;
RunX(0);
}
if (_Down) {
Shtora1 = 1;
RunX(1);
}
}
}
else if (sped_Xt > 0) {
--sped_Xt;
sped_X = sped_Xt;
f_timX = 0;
}
else {
--sped_X;
f_timX = 0;
}
}
}////
}
else {
f_run1X = 1;
no_runX = cur_time;
sbros = cur_time;
f_sbros = 1;
sped_Xt = uskor;
sped_X = 0; // для пропуска 1го тика
}
/////////////////Запуск 3го двигателя если " perem_Z != 0 "
//if (!kalib) {
if (f_timZ) {
if (_UP || _Down) {
if (Menu != 1) {
if (!sped_Z) {
if (!kalib)//Калибровка отк.
{
if (_UP && Shtora2 < max_Sht2) {//3475
RunZ(0);
}
if (_Down && Shtora2 > 0) {
RunZ(1);
}
}
else {//Калибровка Вкл.
if (_UP) {
Shtora2 = 0;
RunZ(0);
}
if (_Down) {
Shtora2 = 1;
RunZ(1);
}
}
}
else if (sped_Zt > 0) {
--sped_Zt;
sped_Z = sped_Zt;
f_timZ = 0;
}
}
else {
--sped_Z;
f_timZ = 0;
}
}////
}
else {
f_run1Z = 1;
no_runZ = cur_time;
sbros = cur_time;
f_sbros = 1;
sped_Zt = uskor;
sped_Z = 0; // для пропуска 1го тика
}
//Снимаем напряжение с катушек двигателя X
if (f_run1X && cur_time - no_runX >= 1000)// закончилось ли время
{
f_run1X = 0;
PORTB &= 0xF0;
}
//Снимаем напряжение с катушек двигателя Z
if (f_run1Z && cur_time - no_runZ >= 1000)// закончилось ли время
{
f_run1Z = 0;
PORTD &= 0xF;
}
}
Добрый вечер. Спасибо, сейчас буду проверять. Я тут немного со схемой повозился, 1 светодиод повесил на 14 пин, 2 светодиод на 15 пин, а на 16 пин прицепил пищалку(при навигации по меню удобно). Можно добавить в скетч?
void Beep() //короткий звук, переключение шторы
{
tone(ton,500,500);
delay(200);
noTone(ton);
}
void Beep_long() //длинный звук, вход и выход из режима калибровки "0"
{
tone(ton,200,1000);
delay(200);
noTone(ton);
}
Проверил скетч...
Со второй шторой всё получилось хорошо, методом тыка настроил высоту - 27500. Ездит хорошо. Полное закрытие или открытие занимает 55 секунд. Немножко не понял в режиме калибровки....как только в него входишь, штору сразу затягивает в барабан, кнопками UP и DOWN возвращаешь на нужное место. С моргающим светодиодом прикольно!
С первой шторой не получится настроить, потому что она должна работать в обратном порядке...моторы стоят не симметрично, здесь нужно инверсию делать.
Вот сделал инверсию попробуйте. Поповоду скорости в стр.72 - StartTimer1(Time_Closk, 2000); можете поиграться с числом, сейчас стоит 2 мс. на меньшем значении у меня стабильно не работает, а у Вас может и будет. По поводу калибровки: при первом входе он сам движется или после установки, при втором заходе тоже?
//********** (РЕЖИМ 1-ШАГ) Крутим с помощью сдвига --рабочая - крутит туда сюда без потери шагов - ускоряет - отключает катушки после бездействия
//PORTB - 8, 9, 10, 11 - Шаговик. && 12-кнопка Menu \ 13-Светодиод 1й штор.
//PORTD - 4, 5, 6, 7 - Шаговик. && 2-кнопка UP \ 3-кнопка DOWN
// А0-Светодиод 2й штор..
#include <CyberLib.h>
#define uskor 2 //Задаем ускорение
//Здесь устанавливаем максимальное кол. шагов для штор
#define max_Sht1 5000
#define max_Sht2 5000
byte n1 = 1;// Сдвигаем 1 бит
byte n3 = 0x10;
bool f_timX = 0;
bool f_timZ = 0;
byte sped_Xt = uskor;//Начальная скорость
byte sped_X = 0; //Ускорение
byte sped_Zt = uskor;//Начальная скорость
byte sped_Z = 0; //Ускорение
bool f_run1X = 0;//Сброс после остановки 2 переменные.
//bool f_run1X = 0;
unsigned long no_runX; //Переменная для прошедшего периода
bool f_run1Z = 0;//Сброс после остановки 2 переменные.
//bool f_run1Z = 0;
unsigned long no_runZ; //Переменная для прошедшего периода
// Переменные для кн.Menu
bool kn_menu;
bool f_menu;
bool f_Mpush;
bool f_Md;
uint8_t Menu = 1;
uint8_t temp_Menu;
bool kalib;
unsigned long menu_dreb;
unsigned long menu_klik;
// Переменные для кн.Up
bool kn_Up;
bool f_Up;
bool state_Up;
bool _UP;
uint32_t Up_dreb;
// Переменные для кн.Down
bool kn_Down;
bool f_Down;
bool state_Down;
bool _Down;
uint32_t Down_dreb;
//сбрасываем UP\Down
uint32_t sbros;
bool f_sbros;
uint32_t cur_time;//Миллис читаем один раз
uint32_t blink_time;//Мигаем в режиме калибровки
int Shtora1 = 50;// количество шагов для полного закрытия шторы 1;
int Shtora2 = 34;// количество шагов для полного закрытия шторы 2
void setup() {
// DDRB пин, 8,9,10,11 - Шаговик, pin 12- вход, 13- Выход
DDRB = DDRB | B00101111;
// pin 8,9,10,11,13 - выход в 0 а входы pin 12, - 0
PORTB = B00000000;
// DDRD, подключенный к двигателю pin 4,5,6,7 как выход,pin2,3 Выход
DDRD = DDRD | B11110000;
// pin 4,5,6,7 - выход в 0 а входы pin 2,3 - 0
PORTD = B00000000;//;
D14_Out; // Led_2
D14_Low;
//Serial.begin(9600);
// Инициализировать TIMER1
StartTimer1(Time_Closk, 2000);
}
void Time_Closk() // Функция прерывания таймера
{
f_timX = 1;
f_timZ = 1;
}
//Функция вращения dvigatel 1
void RunX (bool perem_X)
{
f_timX = 0;
if (perem_X) {
n1 = (n1 >> 1) | (n1 << 3); //Сдвигаем
--Shtora1;
}
else {
n1 = (n1 << 1) | (n1 >> 3); //Сдвигаем
++Shtora1;
}
n1 = 0x0F & n1; //Маскируем кнопки
PORTB = (PORTB & 0xF0) | n1; //Очищаем Младшие биты и пишем туда n1
}
//Функция dvigatel 3
void RunZ (bool perem_Z)
{
f_timZ = 0;
if (perem_Z) {
n3 = (n3 >> 1) | (n3 << 3); //Сдвигаем
--Shtora2;
}
else {
n3 = (n3 << 1) | (n3 >> 3); //Сдвигаем
++Shtora2;
}
n3 = 0xF0 & n3;//Маскируем
PORTD = (PORTD & 0xF) | n3; //Очищаем старшие биты и пишем туда n3
}
void loop() {
cur_time = millis();
///////////////////Проверка кнопки МЕНЮ - АНТИДРЕБЕЗГ
if (D12_Read && !f_menu)
{
menu_dreb = cur_time;
f_menu = 1;
}
if (!D12_Read)
{
kn_menu = 0;
f_menu = 0;
}
if (f_menu && cur_time - menu_dreb >= 20)
{
kn_menu = 1;
if (!f_Mpush) {
menu_klik = cur_time;
f_Mpush = 1;
}
}
if (f_Mpush && !kn_menu && cur_time - menu_klik < 500) {
if (_UP || _Down) {
_UP = 0;
_Down = 0;
}
else Menu++; // Меняем
if (Menu > 3) Menu = 1;
f_Mpush = 0;
}
else if (f_Mpush && !kn_menu && cur_time - menu_klik > 500) {
kalib = !kalib; // Включаем калибровку
f_Mpush = 0;
}
///////////////////////Проверка кнопки UP - АНТИДРЕБЕЗГ
if (D2_Read != f_Up) { //Если сигнал изменился
f_Up = !f_Up;
Up_dreb = cur_time;
}
if (kn_Up == D2_Read && cur_time - Up_dreb > 20) kn_Up = !D2_Read;
// Было нажатие
if (kn_Up && !state_Up) {
if (_UP || _Down) {
_UP = 0;
_Down = 0;
state_Up = 1;
}
else {
_UP = !_UP; // Меняем значение
state_Up = 1;
}
}
if (!kn_Up)state_Up = 0; // Отпустили
///////////////////////Проверка кнопки DOWN - АНТИДРЕБЕЗГ
if (D3_Read != f_Down) { //Если сигнал изменился
f_Down = !f_Down;
Down_dreb = cur_time;
}
if (kn_Down == D3_Read && cur_time - Down_dreb > 20) kn_Down = !D3_Read;
// Было нажатие
if (kn_Down && !state_Down) {
if (_UP || _Down) {
_UP = 0;
_Down = 0;
state_Down = 1;
}
else {
_Down = !_Down; // Меняем значение
state_Down = 1;
}
}
if (!kn_Down)state_Down = 0; // Отпустили
//////////////////////// С кнопками закончили продолжаем логику
if (!kalib)
{
if (Menu != temp_Menu) {
temp_Menu = Menu;
switch (Menu) {
case 1: D13_High; D14_Low; break;
case 2: D13_Low; D14_High; break;
case 3: D13_High; D14_High; break;
}
}
}
else {
if (cur_time - blink_time >= 300)
{
blink_time = cur_time;
switch (Menu) {
case 1: D13_Inv; D14_Low; break;
case 2: D13_Low; D14_Inv; break;
case 3: D13_Inv; D14_Inv; break;
}
}
}
/////////////////////////// Запуск 1го двигателя если " perem_X != 0 "
if (f_timX) {
if (_UP || _Down) {
if (Menu != 2) {
if (!sped_X) {
if (!kalib) { //Калибровка отк.
if (_UP && Shtora1 < max_Sht1) {//3592
RunX(0);
}
if (_Down && Shtora1 > 0) {
RunX(1);
}
}
else { //Калибровка вкл.
if (_UP) {
Shtora1 = 0;
RunX(0);
}
if (_Down) {
Shtora1 = 1;
RunX(1);
}
}
}
else if (sped_Xt > 0) {
--sped_Xt;
sped_X = sped_Xt;
f_timX = 0;
}
else {
--sped_X;
f_timX = 0;
}
}
}////
}
else {
f_run1X = 1;
no_runX = cur_time;
sbros = cur_time;
f_sbros = 1;
sped_Xt = uskor;
sped_X = 0; // для пропуска 1го тика
}
/////////////////Запуск 3го двигателя если " perem_Z != 0 "
//if (!kalib) {
if (f_timZ) {
if (_UP || _Down) {
if (Menu != 1) {
if (!sped_Z) {
if (!kalib)//Калибровка отк.
{
if (_Down && Shtora2 < max_Sht2) {//3475
RunZ(0);
}
if (_UP && Shtora2 > 0) {
RunZ(1);
}
}
else {//Калибровка Вкл.
if (_UP) {
Shtora2 = 0;
RunZ(0);
}
if (_Down) {
Shtora2 = 1;
RunZ(1);
}
}
}
else if (sped_Zt > 0) {
--sped_Zt;
sped_Z = sped_Zt;
f_timZ = 0;
}
}
else {
--sped_Z;
f_timZ = 0;
}
}////
}
else {
f_run1Z = 1;
no_runZ = cur_time;
sbros = cur_time;
f_sbros = 1;
sped_Zt = uskor;
sped_Z = 0; // для пропуска 1го тика
}
//Снимаем напряжение с катушек двигателя X
if (f_run1X && cur_time - no_runX >= 1000)// закончилось ли время
{
f_run1X = 0;
PORTB &= 0xF0;
}
//Снимаем напряжение с катушек двигателя Z
if (f_run1Z && cur_time - no_runZ >= 1000)// закончилось ли время
{
f_run1Z = 0;
PORTD &= 0xF;
}
}
Вот сделал инверсию попробуйте. Поповоду скорости в стр.72 - StartTimer1(Time_Closk, 2000); можете поиграться с числом, сейчас стоит 2 мс. на меньшем значении у меня стабильно не работает, а у Вас может и будет. По поводу калибровки: при первом входе он сам движется или после установки, при втором заходе тоже?
Скетч с инверсией проверил - с первой шторой: нажимаешь кнопку DOWN штора едет вверх, UP - вниз.
Со второй шторой тоже самое.
В режиме калибровки первая штора при нажатии DOWN едет вверх, UP-вниз. Вторая штора DOWN -вниз, UP-вверх.
Еще одна особенность появилась....кнопки UP и DOWN срабатывают со второго нажатия.
P/S похоже я Вас ввожу в заблуждение....первая штора пины:8 9 10 11, вторая штора пины:4 5 6 7
Т.е. получается, что до инверсии вторая штора работала правильно.
Проверил новый скетч.
В режиме калибровки всё отлично! шторы ездят правильно.
В рабочем режиме вторая штора работает, а с первой шторой происходит следущее:
1. При нажатии DOWN штора стоит.
2. При нажатии UP штора заматывается в барабан.
3. Если сначала в режиме калибровки штору опустить полностью и перейти в рабочий режим, то всё работает как надо.
P.S. Погонял шторы одновременно...когда подогнал высоту, все заработало как и хотелось.
Получается, что сначала нужно провести калибровку, а именно опустить шторы в режиме калибровки до нужного положения, выйти из режима калибровки и всё будет работать. Тогда имеет смысл запретить нажатие кнопок UP и DOWN если калибровка не была проведена, это будет один раз при первом запуске, потом когда положения штор и флаг калибровки(шторы уже калибровались) будут храниться в энергонезависимой памяти, разрешить нажатие кнопок.
34 стр. (kalib) присвойте 1, тоесть (bool kalib = 1;) тогда при запуске\перезапуске сразу будет включена калибровка и чтобы выйти изнеё нужно длинное нажатие
34 стр. (kalib) присвойте 1, тоесть (bool kalib = 1;) тогда при запуске\перезапуске сразу будет включена калибровка и чтобы выйти изнеё нужно длинное нажатие
Понял, а можете на 16 пин повесить пищалку? Я пробовал, но что-то не получается. Только для кнопки меню, на короткое нажатие - короткий сигнал, на длинное - длинный сигнал, ну и тон может отличаться.
Хотя если по мне так надобности в пищалке я не вижу потому что кнопка проверяется после отпукания - был клик или нажатие. Светодиоды прекрасно все показывают. При любом писке Вы все равно смотрите на диоды - а что же я включил.
Хотя если по мне так надобности в пищалке я не вижу потому что кнопка проверяется после отпукания - был клик или нажатие. Светодиоды прекрасно все показывают. При любом писке Вы все равно смотрите на диоды - а что же я включил.
Согласен, но всё же....привыкли уже.
Я так думаю ошибка как всегда в делеях?
Заработало!
Теперь осталось сохранять позиции штор в память. Такая реализация как у меня была подойдет?
Еще нужно как то высчитывать оставшееся количество шагов до нужной позиции и сохранять результат калибровки....после отключения/включения питания.
По поводу памяти я Вашу реализацию не разбирал но если работала то должна подойти. Алгоритм предлагаю такой:
1- При загрузке читаем с памяти и присваюем значение перемен. штора1 и штора2
2- После сброса напряжения на двигателе - проверяем изменилось ли значение если да переписуем
3- Не нужно вычислять никаких остатков, просто сохранять перем. штора1(2)
4- калибровку сохранять не нужно - 0 нам звестный также как максимум
Память имеет ограниченный ресурс перезаписи и на сколько Вам ее хватит, Это вопрос, как часто будете дергать штору?
Если что то в тойже CyberLib есть функция работы с помятью
Я по-поводу калибровки хочу спросить...когда мы даем питание на плату, как узнать, что калибровка уже проводилась и в ячейках записано значения положения штор? А если, к примеру, хранить в отдельной ячейке 1 - если калибровка проводилась и 0 - если не проводилась. И если 1, то считать значения из ячеек.
Вопрос: в каком месте скетча сделать запись того, что калибровка провелась?
Чтение и запись значений сделал вот так:
#include <EEPROM.h>
---------------------------------------------------------------------
// чтение
int EEPROM_int_read(int addr) {
byte raw[2];
for(byte i = 0; i < 2; i++) raw[i] = EEPROM.read(addr+i);
int &num = (int&)raw;
return num;
}
// запись
void EEPROM_int_write(int addr, int num) {
if (EEPROM_int_read(addr)!= num){//если сохраняемое отличается
byte raw[2];
(int&)raw = num;
for(byte i = 0; i < 2; i++) EEPROM.write(addr+i, raw[i]);
}
}
------------------------------------------------------------------------
void setup(){
if (EEPROM_int_read(4)!=1)
{
Shtora1=28900;
Shtora2=27500;
}
else
{
Shtora1 = EEPROM_int_read(0);
Shtora2 = EEPROM_int_read(2);
}
}
----------------------------------------------------------------------
void loop(){
//Снимаем напряжение с катушек двигателя X
if (f_run1X && cur_time - no_runX >= 1000)
{
f_run1X = 0;
PORTB &= 0xF0;
f_sbrosX = 1;
if (EEPROM_int_read(0)!=Shtora1)
{
EEPROM_int_write(0, Shtora1); // адрес 0 (+2 байта)
}
}
//Снимаем напряжение с катушек двигателя Z
if (f_run1Z && cur_time - no_runZ >= 1000)
{
f_run1Z = 0;
PORTD &= 0xF;
f_sbrosZ = 1;
if (EEPROM_int_read(2)!=Shtora2)
{
EEPROM_int_write(2, Shtora2); // адрес 0 (+2 байта)
}
}
}
Поповоду калибровки: Глобальная калибровка должна проводиться один раз после перезаписи Ардуино, Это Вы должны знать и без записи в память. Представим что вы провели калибровку и в памяти записали 1, после этого решили обновить программу а у Вас в памяти записано что калибровку проводить не надо, хотя по факту ее надо провести. Так что я не вижу как указать програме что она перепрошыта и нужно калибровать. А поточные - если будут пропуски двигателя и нужно будет подкоректировать штору то Вы будете сами видеть нужно или нет. А вот записать полжение шторы после ее движения - это можно. После перезапуска программа просто востановит положение штор.
#include <EEPROM.h>
---------------------------------------------------------------------
// чтение
int EEPROM_int_read(int addr) {
byte raw[2];
for(byte i = 0; i < 2; i++) raw[i] = EEPROM.read(addr+i);
int &num = (int&)raw;
return num;
}
// запись
void EEPROM_int_write(int addr, int num) {
if (EEPROM_int_read(addr)!= num){//если сохраняемое отличается
byte raw[2];
(int&)raw = num;
for(byte i = 0; i < 2; i++) EEPROM.write(addr+i, raw[i]);
}
}
------------------------------------------------------------------------
void setup(){
Shtora1 = EEPROM_int_read(0);
Shtora2 = EEPROM_int_read(2);
}
----------------------------------------------------------------------
void loop(){
//Снимаем напряжение с катушек двигателя X
if (f_run1X && cur_time - no_runX >= 1000)
{
f_run1X = 0;
PORTB &= 0xF0;
f_sbrosX = 1;
if (EEPROM_int_read(0)!=Shtora1)
{
EEPROM_int_write(0, Shtora1); // адрес 0 (+2 байта)
}
}
//Снимаем напряжение с катушек двигателя Z
if (f_run1Z && cur_time - no_runZ >= 1000)
{
f_run1Z = 0;
PORTD &= 0xF;
f_sbrosZ = 1;
if (EEPROM_int_read(2)!=Shtora2)
{
EEPROM_int_write(2, Shtora2); // адрес 0 (+2 байта)
}
}
}
А если для перевода в режим калибровке включить её с нажатыми кнопками или в сетапе считывать значение определённой ячейки. если там скажем 0xff или 0x00 то считаем что калибровки нет.
Я тоже об этом думал и не нашел решения, только появилось еще больше вопросов, поэтому согласен с Вами. Сейчас залью скетч и проверю. Можно Вас попросить, так сказать "на пальцах" объяснить мне, что означают все эти PORTB &= 0xF0, PORTD &= 0xF, n3 = 0xF0 & n3;//Маскируем PORTD = (PORTD & 0xF) | n3; //Очищаем старшие биты и пишем туда n3, DDRB = DDRB | B00101111;, PORTB = B00000000;, DDRD = DDRD | B11110000;,
PORTD = B00000000;//;
Если в остальном еще можно разобраться, то это для меня темный лес...
Похоже действительно, запись о калибровке не нужна. Сейчас проверил, ставил шторы в разных положениях и отключал питание, после включения все работает как надо, шторы в крайних положениях останавливаются.
А если для перевода в режим калибровке включить её с нажатыми кнопками или в сетапе считывать значение определённой ячейки. если там скажем 0xff или 0x00 то считаем что калибровки нет.
Установить или прочитать это не проблема, Проблема состоит в ее ипользовании - выше я описал.
ИМХО без наличия ООС точное определение положения шторы невозможно. Вот если бы концевики. или по току моторчика определять крайние положения... Но это так - мысли вслух...
Было бы интересно посмотреть видео с работой устройства когда будет всё готово.
ИМХО без наличия ООС точное определение положения шторы невозможно. Вот если бы концевики. или по току моторчика определять крайние положения... Но это так - мысли вслух...
Было бы интересно посмотреть видео с работой устройства когда будет всё готово.
Это еще до переделки, у меня моторы не хотели работать одновременно, а по-одному работали практически так же, только чуть медленнее. Сейчас вообще всё работает изумительно!
Может завтра пересниму....главное не забыть телефон горизонтально держать :)
Сначала хочу Вас поблагодарить! Без Вашей помощи был бы у меня коряво работающий скетч....а сейчас я просто ненарадуюсь :) Спасибо огромное!
Ну а теперь .....у меня в зале окно эркер....
Там установлены 3 шторки. Вас не затруднит переделать этот скетч под Мегу на 3 мотора?
Особенности: на 1 и 3 шторах моторы установлены так же как и в этом скетче, а у 2-ой шторы так же как у 3-ей.
Воистину человеческой наглости нет предела, но без Вашей помощи я еще полгода буду учиться моргать светодиодом, а шторы хочется закончить уже сейчас.
Ладно попробую, только Меги у меня нет испытувать будете Вы
Я завтра попробую переделать часть скетча по аналогии, я так понимаю нужно добавить все как для Z только с Y? Плюс меню увеличить на 1, добавить светодиод.....ну а моторы вращать уже мне не по силам. А еще нужно с пинами определиться...
Кстати, никогда не игрался с шаговыми двигателями, но почитав в интернете возникла следующая мысль - правильно ли я понял, что если взять два двигателя и подключить их парраллельно но с распиновкой у одного в порядке 1-2-3-4 а у другого 4-3-2-1 то мы получим одновременно работающие двигатели крутящиеся в противоположные стороны?
Если это так, то можно было бы взять 3 мосфета, и ими включать и выключать нужные двигатели, подключенные параллельно, а всё управление останется на 4х выводах. ведь ситуация при которой одна штора опускается, а другая поднимается - не предусмотрена ТЗ?
Кстати, никогда не игрался с шаговыми двигателями, но почитав в интернете возникла следующая мысль - правильно ли я понял, что если взять два двигателя и подключить их парраллельно но с распиновкой у одного в порядке 1-2-3-4 а у другого 4-3-2-1 то мы получим одновременно работающие двигатели крутящиеся в противоположные стороны?
Если это так, то можно было бы взять 3 мосфета, и ими включать и выключать нужные двигатели, подключенные параллельно, а всё управление останется на 4х выводах. ведь ситуация при которой одна штора опускается, а другая поднимается - не предусмотрена ТЗ?
На мой взгляд в этом есть зерно. Их не обезтельно включать навстречу, пусть крутят и паралельно.
Я завтра попробую переделать часть скетча по аналогии, я так понимаю нужно добавить все как для Z только с Y? Плюс меню увеличить на 1, добавить светодиод.....ну а моторы вращать уже мне не по силам. А еще нужно с пинами определиться...
Так пойдет? Я просто не знаю, может один порт управлять двумя моторами.
Я еще ничего не подключал, поэтому пока не критично.
И вот изменил скетч, поправьте если что не так. (что не смог сделать я отметил /////////////////////////)
//********** (РЕЖИМ 1-ШАГ) Крутим с помощью сдвига --рабочая - крутит туда сюда без потери шагов - ускоряет - отключает катушки после бездействия
//PORTB - 8, 9, 10, 11 - Шаговик. && 12-кнопка Menu \ 13-Светодиод 1й штор.
//PORTD - 4, 5, 6, 7 - Шаговик. && 2-кнопка UP \ 3-кнопка DOWN
// А0-Светодиод 2й штор..
#include <EEPROM.h>
#include <CyberLib.h>
#define uskor 3 //Задаем ускорение
//Здесь устанавливаем максимальное кол. шагов для штор
#define max_Sht1 28900
#define max_Sht2 30500
#define max_Sht3 28900
byte n1 = 1;// Сдвигаем 1 бит
byte n3 = 0x10;
bool f_timX = 0;
bool f_timY = 0;
bool f_timZ = 0;
byte sped_Xt = uskor;//Начальная скорость
byte sped_X = 0; //Ускорение
byte sped_Yt = uskor;//Начальная скорость
byte sped_Y = 0; //Ускорение
byte sped_Zt = uskor;//Начальная скорость
byte sped_Z = 0; //Ускорение
bool f_run1X = 0;//Сброс после остановки 2 переменные.
unsigned long no_runX; //Переменная для прошедшего периода
bool f_run1Y = 0;//Сброс после остановки 2 переменные.
unsigned long no_runY; //Переменная для прошедшего периода
bool f_run1Z = 0;//Сброс после остановки 2 переменные.
unsigned long no_runZ; //Переменная для прошедшего периода
// Переменные для кн.Menu
bool kn_menu;
bool f_menu;
bool f_Mpush;
bool f_Md;
uint8_t Menu = 1;
uint8_t temp_Menu;
bool kalib;
unsigned long menu_dreb;
unsigned long menu_klik;
// Переменные для кн.Up
bool kn_Up;
bool f_Up;
bool state_Up;
bool _UP;
uint32_t Up_dreb;
// Переменные для кн.Down
bool kn_Down;
bool f_Down;
bool state_Down;
bool _Down;
uint32_t Down_dreb;
//сбрасываем UP\Down
bool f_sbrosZ = 1;
bool f_sbrosY = 1;
bool f_sbrosX = 1;
uint32_t cur_time;//Миллис читаем один раз
uint32_t blink_time;//Мигаем в режиме калибровки
int Shtora1;
int Shtora2;
int Shtora3;
const int ton = 8;//пищалка
// чтение
int EEPROM_int_read(int addr) {
byte raw[2];
for(byte i = 0; i < 2; i++) raw[i] = EEPROM.read(addr+i);
int &num = (int&)raw;
return num;
}
// запись
void EEPROM_int_write(int addr, int num) {
if (EEPROM_int_read(addr)!= num){//если сохраняемое отличается
byte raw[2];
(int&)raw = num;
for(byte i = 0; i < 2; i++) EEPROM.write(addr+i, raw[i]);
}
}
void setup() {
// DDRB пин, 8,9,10,11 - Шаговик, pin 12- вход, 13- Выход
////////////////////////////////////////////////////////////////////// DDRB = DDRB | B00101111;
// pin 8,9,10,11,13 - выход в 0 а входы pin 12, - 0
////////////////////////////////////////////////////////////////////// PORTB = B00000000;
// DDRD, подключенный к двигателю pin 4,5,6,7 как выход,pin2,3 Выход
////////////////////////////////////////////////////////////////////// DDRD = DDRD | B11110000;
// pin 4,5,6,7 - выход в 0 а входы pin 2,3 - 0
////////////////////////////////////////////////////////////////////// PORTD = B00000000;//;
D2_In; //2-кнопка UP
D3_In; //3-кнопка DOWN
D4_In; //4-кнопка MENU
D5_Out; // Led_1
D5_Low;
D6_Out; // Led_2
D6_Low;
D7_Out; // Led_3
D7_Low;
pinMode(ton,OUTPUT);//пищалка
//Serial.begin(9600);
// Инициализировать TIMER1
StartTimer1(Time_Closk, 2200);
Shtora1 = EEPROM_int_read(0);
Shtora2 = EEPROM_int_read(2);
Shtora3 = EEPROM_int_read(4);
}
void Beep() //короткий звук, переключение шторы
{
tone(ton,500,500);
delay(200);
noTone(ton);
}
void Beep_long() //длинный звук, вход и выход из режима калибровки "0"
{
tone(ton,200,1000);
delay(200);
noTone(ton);
}
void Time_Closk() // Функция прерывания таймера
{
f_timX = 1;
f_timY = 1;
f_timZ = 1;
}
//Функция вращения dvigatel 1
void RunX (bool perem_X)
{
f_sbrosX = 0;
f_timX = 0;
if (perem_X) {
n1 = (n1 >> 1) | (n1 << 3); //Сдвигаем
--Shtora1;
}
else {
n1 = (n1 << 1) | (n1 >> 3); //Сдвигаем
++Shtora1;
}
///////////////////////////////////////////////////// n1 = 0x0F & n1; //Маскируем кнопки
///////////////////////////////////////////////////// PORTB = (PORTB & 0xF0) | n1; //Очищаем Младшие биты и пишем туда n1
}
//Функция dvigatel 2
void RunY (bool perem_Y)
{
f_sbrosY = 0;
f_timY = 0;
if (perem_Y) {
n3 = (n3 >> 1) | (n3 << 3); //Сдвигаем
--Shtora2;
}
else {
n3 = (n3 << 1) | (n3 >> 3); //Сдвигаем
++Shtora2;
}
/////////////////////////////////////////////////// n3 = 0xF0 & n3;//Маскируем
/////////////////////////////////////////////////// PORTD = (PORTD & 0xF) | n3; //Очищаем старшие биты и пишем туда n3
}
//Функция dvigatel 3
void RunZ (bool perem_Z)
{
f_sbrosZ = 0;
f_timZ = 0;
if (perem_Z) {
n3 = (n3 >> 1) | (n3 << 3); //Сдвигаем
--Shtora3;
}
else {
n3 = (n3 << 1) | (n3 >> 3); //Сдвигаем
++Shtora3;
}
////////////////////////////////////////////////// n3 = 0xF0 & n3;//Маскируем
////////////////////////////////////////////////// PORTD = (PORTD & 0xF) | n3; //Очищаем старшие биты и пишем туда n3
}
void loop() {
cur_time = millis();
///////////////////Проверка кнопки МЕНЮ - АНТИДРЕБЕЗГ
if (D4_Read && !f_menu)
{
menu_dreb = cur_time;
f_menu = 1;
}
if (!D4_Read)
{
kn_menu = 0;
f_menu = 0;
}
if (f_menu && cur_time - menu_dreb >= 20)
{
kn_menu = 1;
if (!f_Mpush) {
menu_klik = cur_time;
f_Mpush = 1;
}
}
//Был клик
if (f_Mpush && !kn_menu && cur_time - menu_klik < 1000) {
if (_UP || _Down) {
_UP = 0;
_Down = 0;
}
else Menu++, Beep(); // Меняем
if (Menu > 4) Menu = 1;
f_Mpush = 0;
}
//Было нажатие
else if (f_Mpush && !kn_menu && cur_time - menu_klik > 1000) {
Beep_long();
kalib = !kalib; // Включаем калибровку
f_Mpush = 0;
} ///////////////////////Проверка кнопки UP - АНТИДРЕБЕЗГ
if (D2_Read != f_Up) { //Если сигнал изменился
f_Up = !f_Up;
Up_dreb = cur_time;
}
if (kn_Up == D2_Read && cur_time - Up_dreb > 20) kn_Up = !D2_Read;
// Было нажатие
if (kn_Up && !state_Up) {
if (_UP || _Down) {
_UP = 0;
_Down = 0;
state_Up = 1;
}
else {
_UP = !_UP; // Меняем значение
state_Up = 1;
}
}
if (!kn_Up)state_Up = 0; // Отпустили
///////////////////////Проверка кнопки DOWN - АНТИДРЕБЕЗГ
if (D3_Read != f_Down) { //Если сигнал изменился
f_Down = !f_Down;
Down_dreb = cur_time;
}
if (kn_Down == D3_Read && cur_time - Down_dreb > 20) kn_Down = !D3_Read;
// Было нажатие
if (kn_Down && !state_Down) {
if (_UP || _Down) {
_UP = 0;
_Down = 0;
state_Down = 1;
}
else {
_Down = !_Down; // Меняем значение
state_Down = 1;
}
}
if (!kn_Down)state_Down = 0; // Отпустили
//////////////////////// С кнопками закончили продолжаем логику
if (!kalib)
{
if (Menu != temp_Menu) {
temp_Menu = Menu;
switch (Menu) {
case 1: D5_High; D6_Low; D7_Low; break;
case 2: D5_Low; D6_High; D7_Low; break;
case 3: D5_Low; D6_Low; D7_High; break;
case 4: D5_High; D6_High; D7_High; break;
}
}
}
else {
if (cur_time - blink_time >= 300)
{
blink_time = cur_time;
switch (Menu) {
case 1: D5_Inv; D6_Low; D7_Low; break;
case 2: D5_Low; D6_Inv; D7_Low; break;
case 3: D5_Low; D6_Low; D7_Inv break;
case 4: D5_Inv; D6_Inv; D7_Inv break;
}
}
}
/////////////////////////// Запуск 1го двигателя если " perem_X != 0 "
if (f_timX) {
if (_UP || _Down) {
if (Menu != 1) {
if (!sped_X) {
if (!kalib) { //Калибровка отк.
if (_Down && Shtora1 < max_Sht1) {
RunX(0);
}
if (_UP && Shtora1 > 0) {
RunX(1);
}
}
else { //Калибровка вкл.
if (_Down) {
Shtora1 = 0;
RunX(0);
}
if (_UP) {
Shtora1 = 1;
RunX(1);
}
}
//Три поверки для разгона
if (sped_Xt > 0) {
--sped_Xt;
sped_X = sped_Xt;
// f_timX = 0;
}
}
else {
--sped_X;
f_timX = 0;
}
}
}////
else {
sped_Xt = uskor;
sped_X = 0;
}
}
else { //Для снятия напряжения
f_run1X = 1;
no_runX = cur_time;
}
/////////////////Запуск 2го двигателя если " perem_Y != 0 "
if (f_timY) {
if (_UP || _Down) {
if (Menu != 2) {
if (!sped_Y) {
if (!kalib)//Калибровка отк.
{
if (_UP && Shtora2 < max_Sht2) {
RunY(0);
}
if (_Down && Shtora2 > 0) {
RunY(1);
}
}
else {//Калибровка Вкл.
if (_UP) {
Shtora2 = 0;
RunY(0);
}
if (_Down) {
Shtora2 = 1;
RunY(1);
}
}
//Три поверки для разгона
if (sped_Yt > 0) {
--sped_Yt;
sped_Y = sped_Yt;
f_timY = 0;
}
}
else {
--sped_Y;
f_timY = 0;
}
}
}////
else {
sped_Yt = uskor;
sped_Y = 0;
}
}
else { //Для снятия напряжения
f_run1Y = 1;
no_runY = cur_time;
}
/////////////////Запуск 3го двигателя если " perem_Z != 0 "
if (f_timZ) {
if (_UP || _Down) {
if (Menu != 3) {
if (!sped_Z) {
if (!kalib)//Калибровка отк.
{
if (_UP && Shtora3 < max_Sht3) {
RunZ(0);
}
if (_Down && Shtora3 > 0) {
RunZ(1);
}
}
else {//Калибровка Вкл.
if (_UP) {
Shtora3 = 0;
RunZ(0);
}
if (_Down) {
Shtora3 = 1;
RunZ(1);
}
}
//Три поверки для разгона
if (sped_Zt > 0) {
--sped_Zt;
sped_Z = sped_Zt;
f_timZ = 0;
}
}
else {
--sped_Z;
f_timZ = 0;
}
}
}////
else {
sped_Zt = uskor;
sped_Z = 0;
}
}
else { //Для снятия напряжения
f_run1Z = 1;
no_runZ = cur_time;
}
//Возврат по достижению конечной точки
if (f_sbrosZ && f_sbrosY && f_sbrosX) {
_UP = 0;
_Down = 0;
}
//Снимаем напряжение с катушек двигателя X
if (f_run1X && cur_time - no_runX >= 1000)
{
f_run1X = 0;
////////////////////////////////////////////////////////////// PORTB &= 0xF0;
f_sbrosX = 1;
if (EEPROM_int_read(0)!=Shtora1)
{
EEPROM_int_write(0, Shtora1); // адрес 0 (+2 байта)
}
}
//Снимаем напряжение с катушек двигателя Y
if (f_run1Y && cur_time - no_runY >= 1000)
{
f_run1Y = 0;
///////////////////////////////////////////////////////////// PORTD &= 0xF;
f_sbrosY = 1;
if (EEPROM_int_read(2)!=Shtora2)
{
EEPROM_int_write(2, Shtora2); // адрес 2 (+2 байта)
}
}
//Снимаем напряжение с катушек двигателя Z
if (f_run1Z && cur_time - no_runZ >= 1000)
{
f_run1Z = 0;
/////////////////////////////////////////////////////////// PORTD &= 0xF;
f_sbrosZ = 1;
if (EEPROM_int_read(4)!=Shtora3)
{
EEPROM_int_write(4, Shtora3); // адрес 4 (+2 байта)
}
}
}
Я просто не знаю, может один порт управлять двумя моторами.
а почему бы и нет? Он же через ULN работает.
Кстати, ИМХО, есть смысл провести эксперимент - подключить два мотора, как я писал выше. Что бы они от одного порта крутились в разные стороны. Тогда будет достаточно 10 лап на 3 кнопки, 3 мотора и 4 вывода управления
Кстати, ИМХО, есть смысл провести эксперимент - подключить два мотора, как я писал выше. Что бы они от одного порта крутились в разные стороны. Тогда будет достаточно 10 лап на 3 кнопки, 3 мотора и 4 вывода управления
Проверил Ваше предположение....верно, можно все три мотора подключить к четырем пинам по схеме 1-2-3-4, причем один мотор подключил 4-3-2-1....нажимаешь кнопку "вправо" крутятся два в право, а один влево и наоборот. Удерживая вращение, снимал перемычку на драйвере (как Вы и сказали типа мосфетом дал команду), нужный мотор останавливался, остальные крутятся.
Получается, что нужно дать команду на вращение и мосфетами выбирать нужный мотор или все сразу. А по мин или макс положению выключать.
Давайте пока попробуем на Мега, которой у меня нет и испытать не могу
Испытывал на столе, моторы разложил как они должны стоять на шторах. Сначала была небольшая путаница, моторы крутились не в те стороны какие нужно....подключал вот так:
//PORTA - к двигателю X (22,23,24,25,) - как выход
//PORTC - к двигателю Y,Z (37,36,35,34) (33,32,31,30) как выход
Потом переподключил вот так:
//PORTA - к двигателю X (25,24,23,22,) - как выход
//PORTC - к двигателю Y,Z (37,36,35,34) (30,31,32,33) как выход
Моторы стали крутиться в нужную сторону, но Y - это 3 мотор, а Z - 2 мотор.
В принципе можно "забить" на это, подключить как нужно, и пофиг как это в скетче называется. В комментарии написать, что Z - второй мотор (30,31,32,33), Y - третий мотор (37,36,35,34).
ИМХО надо или класс делать, или структуру. А их них массив - размерностью в количество двигателей.
тогда
switch (Menu) {
case 1:
if (_Down)Shtora1++;
if (_UP)Shtora1--;
break;
case 2:
if (_Down)Shtora2++;
if (_UP)Shtora2--;
break;
case 3:
if (_Down)Shtora3++;
if (_UP)Shtora3--;
break;
case 4:
if (_Down) {
if (_Mofs1)Shtora1++;
if (_Mofs2)Shtora2++;
if (_Mofs3)Shtora3++;
}
if (_UP) {
if (_Mofs1)Shtora1--;
if (_Mofs2)Shtora2--;
if (_Mofs3)Shtora3--;
}
break;
}
Будет выглядеть как
for( int i = 0; i < MotorCount; i++)
{
if( motorArr[i].State == HIGH )
{
motorArr[i].Shtora += direction; // direction 1 в одну сторону, -1 в другую.
}
}
//********** (РЕЖИМ 1-ШАГ) Крутим с помощью сдвига --рабочая - крутит туда сюда без потери шагов - ускоряет - отключает катушки после бездействия //PORTB - 8, 9, 10, 11 - Шаговик. && 12-кнопка Menu \ 13-Светодиод 1й штор. //PORTD - 4, 5, 6, 7 - Шаговик. && 2-кнопка UP \ 3-кнопка DOWN // А0-Светодиод 2й штор.. #include <CyberLib.h> //Задаем ускорение #define uskor 3 byte n1 = 1;// Сдвигаем 1 бит byte n3 = 0x10; byte f_tim = 0; byte sped_Xt = uskor;//Начальная скорость byte sped_X = 0; //Ускорение byte sped_Zt = uskor;//Начальная скорость byte sped_Z = 0; //Ускорение bool f_run1X = 0;//Сброс после остановки 3 переменные. bool f_run2X = 0; unsigned long no_runX; //Переменная для прошедшего периода bool f_run1Z = 0;//Сброс после остановки 3 переменные. bool f_run2Z = 0; unsigned long no_runZ; //Переменная для прошедшего периода // Переменные для кн.Menu bool kn_menu; bool f_menu; bool f_Mpush; bool f_Md; uint8_t Menu = 1; uint8_t temp_Menu; bool kalib; unsigned long menu_dreb; unsigned long menu_klik; // Переменные для кн.Up bool kn_Up; bool f_Up; bool state_Up; bool _UP; uint32_t Up_dreb; // Переменные для кн.Down bool kn_Down; bool f_Down; bool state_Down; bool _Down; uint32_t Down_dreb; uint32_t sbros; bool f_sbros; uint32_t cur_time; uint32_t blink_time; bool f_blink; int Shtora1 = 50;// количество шагов для полного закрытия шторы 1; int Shtora2 = 34;// количество шагов для полного закрытия шторы 2 void setup() { // DDRB пин, 8,9,10,11 - Шаговик, pin 12- вход, 13- Выход DDRB = DDRB | B00101111; // pin 8,9,10,11,13 - выход в 0 а входы pin 12, - 0 PORTB = B00000000; // DDRD, подключенный к двигателю pin 4,5,6,7 как выход,pin2,3 Выход DDRD = DDRD | B11110000; // pin 4,5,6,7 - выход в 0 а входы pin 2,3 - 0 PORTD = B00000000;//; D14_Out; // Led_2 D14_Low; Serial.begin(9600); // Инициализировать TIMER1 noInterrupts (); // отключить все прерывания TCCR1A = 0; TCCR1B = 0; TCNT1 = 0; OCR1A = 125; // сравнить регистр (скорость!!!(2ms=125 - если медленнее - УВЕЛИЧИВАЕМ) TCCR1B |= (1 << WGM12); // Режим СТС TCCR1B |= (1 << CS12); // 256 делитель TIMSK1 |= (1 << OCIE1A ); // включить таймер сравнить прерываний interrupts(); // включить все прерывания } ISR (TIMER1_COMPA_vect) // Функция прерывания таймера { // Serial.println(f_tim); f_tim = B1111; } //Функция вращения dvigatel 1 void RunX (bool perem_X) { f_tim &= B1110; if (perem_X) { n1 = (n1 >> 1) | (n1 << 3); //Сдвигаем --Shtora1; } else { n1 = (n1 << 1) | (n1 >> 3); //Сдвигаем ++Shtora1; } n1 = 0x0F & n1; //Маскируем кнопки PORTB = (PORTB & 0xF0) | n1; //Очищаем Младшие биты и пишем туда n1 } //Функция dvigatel 3 void RunZ (bool perem_Z) { f_tim &= B1011; if (perem_Z) { n3 = (n3 >> 1) | (n3 << 3); //Сдвигаем --Shtora2; } else { n3 = (n3 << 1) | (n3 >> 3); //Сдвигаем ++Shtora2; } n3 = 0xF0 & n3;//Маскируем PORTD = (PORTD & 0xF) | n3; //Очищаем старшие биты и пишем туда n3 //Serial.println(n3); } void loop() { static bool tem_UP; if (_UP != tem_UP) { tem_UP = _UP; Serial.print("UP- "); Serial.println(_UP); } static bool tem_Down; if (_Down != tem_Down) { tem_Down = _Down; Serial.print("Down- "); Serial.println(_Down); } cur_time = millis(); ///////////////////Проверка кнопки МЕНЮ - АНТИДРЕБЕЗГ if (D12_Read && !f_menu) { menu_dreb = cur_time; f_menu = 1; } if (!D12_Read) { kn_menu = 0; f_menu = 0; } if (f_menu && cur_time - menu_dreb >= 20) { kn_menu = 1; if (!f_Mpush) { menu_klik = cur_time; f_Mpush = 1; } } if (f_Mpush && !kn_menu && cur_time - menu_klik < 500) { if (_UP || _Down) { _UP = 0; _Down = 0; } else Menu++; // Меняем if (Menu > 3) Menu = 1; f_Mpush = 0; } else if (f_Mpush && !kn_menu && cur_time - menu_klik > 500) { kalib = !kalib; // Включаем калибровку Serial.print("kalib- "); Serial.println(kalib); f_Mpush = 0; } ///////////////////////Проверка кнопки UP - АНТИДРЕБЕЗГ if (D2_Read != f_Up) { //Если сигнал изменился f_Up = !f_Up; Up_dreb = cur_time; } if (kn_Up == D2_Read && cur_time - Up_dreb > 20) kn_Up = !D2_Read; // Было нажатие if (kn_Up && !state_Up) { if (_UP || _Down) { _UP = 0; _Down = 0; state_Up = 1; } else { _UP = !_UP; // Меняем значение state_Up = 1; } } if (!kn_Up)state_Up = 0; // Отпустили ///////////////////////Проверка кнопки DOWN - АНТИДРЕБЕЗГ if (D3_Read != f_Down) { //Если сигнал изменился f_Down = !f_Down; Down_dreb = cur_time; } if (kn_Down == D3_Read && cur_time - Down_dreb > 20) kn_Down = !D3_Read; // Было нажатие if (kn_Down && !state_Down) { if (_UP || _Down) { _UP = 0; _Down = 0; state_Down = 1; } else { _Down = !_Down; // Меняем значение state_Down = 1; } } if (!kn_Down)state_Down = 0; // Отпустили //////////////////////// С кнопками закончили продолжаем логику if (!kalib) { if (Menu != temp_Menu) { temp_Menu = Menu; Serial.print("Menu- "); Serial.println(Menu); switch (Menu) { case 1: D13_High; D14_Low; break; case 2: D13_Low; D14_High; break; case 3: D13_High; D14_High; break; } } } else { if (cur_time - blink_time >= 300) { blink_time = cur_time; switch (Menu) { case 1: D13_Inv; D14_Low; break; case 2: D13_Low; D14_Inv; break; case 3: D13_Inv; D14_Inv; break; } } } /////////////////////////// Запуск 1го двигателя если " perem_X != 0 " //if (!kalib) { if (_UP || _Down) { if (Menu != 2) { if (f_tim & (1 << 0)) { if (!sped_X) { if (!kalib)//Калибровка отк. { if (_UP && Shtora1 < 50) {//3592 RunX(0); Serial.print("Shtora1- "); Serial.println(Shtora1); } if (_Down && Shtora1 > 0) { RunX(1); Serial.print("Shtora1- "); Serial.println(Shtora1); } } else { //Калибровка вкл. if (_UP) { Shtora1 = 0; RunX(0); Serial.print("Shtora1- "); Serial.println(Shtora1); } if (_Down) { Shtora1 = 1; RunX(1); Serial.print("Shtora1- "); Serial.println(Shtora1); } } if (sped_Xt > 0) { --sped_Xt; sped_X = sped_Xt; } } else { --sped_X; f_tim &= B1110; } }//// else { f_run2X = 1; no_runX = cur_time; } } } else { sped_Xt = uskor; sped_X = 0; // для пропуска 1го тика } //} /////////////////Запуск 3го двигателя если " perem_Z != 0 " //if (!kalib) { if (_UP || _Down) { if (Menu != 1) { if (f_tim & (1 << 2)) { if (!sped_Z) { if (!kalib)//Калибровка отк. { if (_UP && Shtora2 < 34) {//3475 RunZ(0); Serial.print("Shtora2- "); Serial.println(Shtora2); } if (_Down && Shtora2 > 0) { RunZ(1); Serial.print("Shtora2- "); Serial.println(Shtora2); } } else {//Калибровка Вкл. if (_UP) { Shtora2 = 0; RunZ(0); Serial.print("Shtora2- "); Serial.println(Shtora2); } if (_Down) { Shtora2 = 1; RunZ(1); Serial.print("Shtora2- "); Serial.println(Shtora2); } } if (sped_Zt > 0) { --sped_Zt; sped_Z = sped_Zt; } } else { --sped_Z; f_tim &= B1011; } }//// else { f_run2Z = 1; no_runZ = cur_time; } } } else { sped_Zt = uskor; sped_Z = 0; // для пропуска 1го тика } //Если достигли конца сбрасываем UP\Down if (f_tim != 15) { sbros = cur_time; f_sbros = 0; } if (!f_sbros && cur_time - sbros > 1500) { f_sbros = 1; _UP = 0; _Down = 0; } //Снимаем напряжение с катушек двигателя X if (f_run2X && cur_time - no_runX >= 1000)// закончилось ли время { f_run2X = 0; PORTB &= 0xF0; } //Снимаем напряжение с катушек двигателя Z if (f_run2Z && cur_time - no_runZ >= 1000)// закончилось ли время { f_run2Z = 0; PORTD &= 0xF; } }А оба зачем? Две шторы одновременно смысла нет калибровать. У нас самое главное не работает.....моторы не крутятся и кренка сильно греется!!! В симуляторе светодиоды бегают прикольно, а реальная сборка работать не хочет. Первый скетч работает изумительно, для режима калибровки самое то....пока держишь кнопку - мотор крутится, отпустил - остановился. Вот этот скетч.
//********** (РЕЖИМ 1-ШАГ) Крутим с помощью сдвига --рабочая - крутит туда сюда без потери шагов - ускоряет - отключает катушки после бездействия //PORTB - 8, 9, 10, 11 - Шаговик. && 12, 13 - Вход сигнал от 2х кнопок (влево - вправо) //PORTD - 4, 5, 6, 7 - Шаговик. && 2, 3 - остаются для переферии #define uskor 2 //Задаем ускорение byte n1 = 1;// Сдвигаем 1 бит byte n3 = 0x10; byte f_tim = 0; long int perem_X = 0; long int perem_Z = 0; byte sped_Xt = uskor;//Начальная скорость byte sped_X = 0; //Ускорение byte sped_Zt = uskor;//Начальная скорость byte sped_Z = 0; //Ускорение bool f_run1X = 0;//Сброс после остановки 3 переменные. bool f_run2X = 0; unsigned long no_runX; //Переменная для прошедшего периода bool f_run1Z = 0;//Сброс после остановки 3 переменные. bool f_run2Z = 0; unsigned long no_runZ; //Переменная для прошедшего периода void setup() { // пин, 8, 9, 10, 11 - Шаговик, 2, 3- переферия DDRB = 0xCF; //Устанавлюем значение выходов в 0 а входы - подтягивающий резистор PORTB = 0x30; // PORTD, подключенный к двигателю 3 как выход, Две кнопки с подтяжкой pin2-3 DDRD = DDRD | B11110000; //Устанавлюем значение выходов PORTD в 0 PORTD = PORTD | B00001100;//x0F; // Serial.begin(9600); // Инициализировать TIMER1 noInterrupts (); // отключить все прерывания TCCR1A = 0; TCCR1B = 0; TCNT1 = 0; OCR1A = 125; // сравнить регистр (скорость!!!(2ms=125 - если медлиннее - УВЕЛИЧУЕМ) TCCR1B |= (1 << WGM12); // Режим СТС TCCR1B |= (1 << CS12); // 256 делитель TIMSK1 |= (1 << OCIE1A ); // включить таймер сравнить прерываний interrupts(); // включить все прерывания } ISR (TIMER1_COMPA_vect) // Функция прерывания таймера { // Serial.println(f_tim); f_tim = B1111; } //Функция вращения dvigatel 1 void RunX () { f_tim &= B1110; if (perem_X > 0) { n1 = (n1 >> 1) | (n1 << 3); //Сдвигаем --perem_X; } else { n1 = (n1 << 1) | (n1 >> 3); //Сдвигаем ++perem_X; } n1 = 0x0F & n1; //Маскируем кнопки PORTB = (PORTB & 0xF0) | n1; //Очищаем Младшие биты и пишем туда n1 } //Функция dvigatel 3 void RunZ () { f_tim &= B1011; if (perem_Z > 0) { n3 = (n3 >> 1) | (n3 << 3); //Сдвигаем --perem_Z; } else { n3 = (n3 << 1) | (n3 >> 3); //Сдвигаем ++perem_Z; } n3 = 0xF0 & n3;//Маскируем PORTD = (PORTD & 0xF) | n3; //Очищаем старшие биты и пишем туда n3 //Serial.println(n3); } void loop() { //Кнопки 1 и 2 служат для демонстрации работы. Считается замкнутой при подаче МИНУСА if ((PIND & (1 << 3))) //проверяем кнопку 1 - нажали? Можно использовать if(!digitalRead(2)) { //Задаем количество шагов для дв.- ВПРАВО "perem_X = Количеству шагов;" perem_X = 10; perem_Z = -10; } //else perem_X = 0; // ВНИМАНИЕ если задаём количество шагов - эту строчку удаляем!!! if ((PIND & (1 << 2))) //проверяем кнопку 2 - нажали? Можно использовать if(!digitalRead(3)) { //Задаем количество шагов для дв.- ВЛЕВО "perem_X = -Количеству шагов;" perem_X = -10; perem_Z = 10; } /////////////////////////// Запуск 1го двигателя если " perem_X != 0 " if (perem_X != 0) { f_run1X = 1; f_run2X = 0; if (f_tim & (1 << 0)) { if (!sped_X) { RunX(); if (sped_Xt > 0) { --sped_Xt; sped_X = sped_Xt; } } else { --sped_X; f_tim &= B1110; } } } else { sped_Xt = uskor; sped_X = 0; // для пропуска 1го тика } /////////////////Запуск 3го двигателя если " perem_Z != 0 " if (perem_Z != 0) { f_run1Z = 1; f_run2Z = 0; if (f_tim & (1 << 2)) { if (!sped_Z) { RunZ(); if (sped_Zt > 0) { --sped_Zt; sped_Z = sped_Zt; } } else { --sped_Z; f_tim &= B1011; } } } else { sped_Zt = uskor; sped_Z = 0; // для пропуска 1го тика } //Снимаеммаем напряжение с катушек двигателя X if (f_run1X && perem_X == 0) //Служит для запуска отключения катушек { f_run1X = 0; f_run2X = 1; no_runX = millis(); } if (f_run2X && millis() - no_runX >= 1000)// Проверяем закончилось ли время { f_run2X = 0; //Снимаем напряжение с катушек PORTB &= 0xF0; } //Снимаеммаем напряжение с катушек двигателя Z if (f_run1Z && perem_Z == 0) //Служит для запуска отключения катушек { f_run1Z = 0; f_run2Z = 1; no_runZ = millis(); } if (f_run2Z && millis() - no_runZ >= 1000)// Проверяем закончилось ли время { f_run2Z = 0; //Снимаем напряжение с катушек PORTD &= 0xF; } }По-поводу калибровки я считаю, что правильней калибровать "0" вверху, т.е. начальное положение из которого штора разматывается и чтобы штора не замоталась в барабан.
Вот скетч провери его на живой ардуине, правда на однм двигателе, крутит отключает, ничего не греется. Проблему скорости давал Сериал, пришлось его удалить. В принцепе он нужен только для настройки. А так пока искал причину по скорости то таймер поменял и так помелочам. Ммаксимальную высоту будете ставить в самом начале _ там написано
//********** (РЕЖИМ 1-ШАГ) Крутим с помощью сдвига --рабочая - крутит туда сюда без потери шагов - ускоряет - отключает катушки после бездействия //PORTB - 8, 9, 10, 11 - Шаговик. && 12-кнопка Menu \ 13-Светодиод 1й штор. //PORTD - 4, 5, 6, 7 - Шаговик. && 2-кнопка UP \ 3-кнопка DOWN // А0-Светодиод 2й штор.. #include <CyberLib.h> #define uskor 5 //Задаем ускорение //Здесь устанавливаем максимальное кол. шагов для штор #define max_Sht1 5000 #define max_Sht2 5000 byte n1 = 1;// Сдвигаем 1 бит byte n3 = 0x10; bool f_timX = 0; bool f_timZ = 0; //long int perem_X = 0; //long int perem_Z = 0; byte sped_Xt = uskor;//Начальная скорость byte sped_X = 0; //Ускорение byte sped_Zt = uskor;//Начальная скорость byte sped_Z = 0; //Ускорение bool f_run1X = 0;//Сброс после остановки 2 переменные. //bool f_run1X = 0; unsigned long no_runX; //Переменная для прошедшего периода bool f_run1Z = 0;//Сброс после остановки 2 переменные. //bool f_run1Z = 0; unsigned long no_runZ; //Переменная для прошедшего периода // Переменные для кн.Menu bool kn_menu; bool f_menu; bool f_Mpush; bool f_Md; uint8_t Menu = 1; uint8_t temp_Menu; bool kalib; unsigned long menu_dreb; unsigned long menu_klik; // Переменные для кн.Up bool kn_Up; bool f_Up; bool state_Up; bool _UP; uint32_t Up_dreb; // Переменные для кн.Down bool kn_Down; bool f_Down; bool state_Down; bool _Down; uint32_t Down_dreb; //сбрасываем UP\Down uint32_t sbros; bool f_sbros; uint32_t cur_time;//Миллис читаем один раз uint32_t blink_time;//Мигаем в режиме калибровки int Shtora1 = 50;// количество шагов для полного закрытия шторы 1; int Shtora2 = 34;// количество шагов для полного закрытия шторы 2 void setup() { // DDRB пин, 8,9,10,11 - Шаговик, pin 12- вход, 13- Выход DDRB = DDRB | B00101111; // pin 8,9,10,11,13 - выход в 0 а входы pin 12, - 0 PORTB = B00000000; // DDRD, подключенный к двигателю pin 4,5,6,7 как выход,pin2,3 Выход DDRD = DDRD | B11110000; // pin 4,5,6,7 - выход в 0 а входы pin 2,3 - 0 PORTD = B00000000;//; D14_Out; // Led_2 D14_Low; //Serial.begin(9600); // Инициализировать TIMER1 StartTimer1(Time_Closk, 2000); } void Time_Closk() // Функция прерывания таймера { f_timX = 1; f_timZ = 1; } //Функция вращения dvigatel 1 void RunX (bool perem_X) { f_timX = 0; if (perem_X) { n1 = (n1 >> 1) | (n1 << 3); //Сдвигаем --Shtora1; } else { n1 = (n1 << 1) | (n1 >> 3); //Сдвигаем ++Shtora1; } n1 = 0x0F & n1; //Маскируем кнопки PORTB = (PORTB & 0xF0) | n1; //Очищаем Младшие биты и пишем туда n1 } //Функция dvigatel 3 void RunZ (bool perem_Z) { f_timZ = 0; if (perem_Z) { n3 = (n3 >> 1) | (n3 << 3); //Сдвигаем --Shtora2; } else { n3 = (n3 << 1) | (n3 >> 3); //Сдвигаем ++Shtora2; } n3 = 0xF0 & n3;//Маскируем PORTD = (PORTD & 0xF) | n3; //Очищаем старшие биты и пишем туда n3 } void loop() { cur_time = millis(); ///////////////////Проверка кнопки МЕНЮ - АНТИДРЕБЕЗГ if (D12_Read && !f_menu) { menu_dreb = cur_time; f_menu = 1; } if (!D12_Read) { kn_menu = 0; f_menu = 0; } if (f_menu && cur_time - menu_dreb >= 20) { kn_menu = 1; if (!f_Mpush) { menu_klik = cur_time; f_Mpush = 1; } } if (f_Mpush && !kn_menu && cur_time - menu_klik < 500) { if (_UP || _Down) { _UP = 0; _Down = 0; } else Menu++; // Меняем if (Menu > 3) Menu = 1; f_Mpush = 0; } else if (f_Mpush && !kn_menu && cur_time - menu_klik > 500) { kalib = !kalib; // Включаем калибровку f_Mpush = 0; } ///////////////////////Проверка кнопки UP - АНТИДРЕБЕЗГ if (D2_Read != f_Up) { //Если сигнал изменился f_Up = !f_Up; Up_dreb = cur_time; } if (kn_Up == D2_Read && cur_time - Up_dreb > 20) kn_Up = !D2_Read; // Было нажатие if (kn_Up && !state_Up) { if (_UP || _Down) { _UP = 0; _Down = 0; state_Up = 1; } else { _UP = !_UP; // Меняем значение state_Up = 1; } } if (!kn_Up)state_Up = 0; // Отпустили ///////////////////////Проверка кнопки DOWN - АНТИДРЕБЕЗГ if (D3_Read != f_Down) { //Если сигнал изменился f_Down = !f_Down; Down_dreb = cur_time; } if (kn_Down == D3_Read && cur_time - Down_dreb > 20) kn_Down = !D3_Read; // Было нажатие if (kn_Down && !state_Down) { if (_UP || _Down) { _UP = 0; _Down = 0; state_Down = 1; } else { _Down = !_Down; // Меняем значение state_Down = 1; } } if (!kn_Down)state_Down = 0; // Отпустили //////////////////////// С кнопками закончили продолжаем логику if (!kalib) { if (Menu != temp_Menu) { temp_Menu = Menu; switch (Menu) { case 1: D13_High; D14_Low; break; case 2: D13_Low; D14_High; break; case 3: D13_High; D14_High; break; } } } else { if (cur_time - blink_time >= 300) { blink_time = cur_time; switch (Menu) { case 1: D13_Inv; D14_Low; break; case 2: D13_Low; D14_Inv; break; case 3: D13_Inv; D14_Inv; break; } } } /////////////////////////// Запуск 1го двигателя если " perem_X != 0 " if (f_timX) { if (_UP || _Down) { if (Menu != 2) { if (!sped_X) { if (!kalib) { //Калибровка отк. if (_UP && Shtora1 < max_Sht1) {//3592 RunX(0); } if (_Down && Shtora1 > 0) { RunX(1); } } else { //Калибровка вкл. if (_UP) { Shtora1 = 0; RunX(0); } if (_Down) { Shtora1 = 1; RunX(1); } } } else if (sped_Xt > 0) { --sped_Xt; sped_X = sped_Xt; f_timX = 0; } else { --sped_X; f_timX = 0; } } }//// } else { f_run1X = 1; no_runX = cur_time; sbros = cur_time; f_sbros = 1; sped_Xt = uskor; sped_X = 0; // для пропуска 1го тика } /////////////////Запуск 3го двигателя если " perem_Z != 0 " //if (!kalib) { if (f_timZ) { if (_UP || _Down) { if (Menu != 1) { if (!sped_Z) { if (!kalib)//Калибровка отк. { if (_UP && Shtora2 < max_Sht2) {//3475 RunZ(0); } if (_Down && Shtora2 > 0) { RunZ(1); } } else {//Калибровка Вкл. if (_UP) { Shtora2 = 0; RunZ(0); } if (_Down) { Shtora2 = 1; RunZ(1); } } } else if (sped_Zt > 0) { --sped_Zt; sped_Z = sped_Zt; f_timZ = 0; } } else { --sped_Z; f_timZ = 0; } }//// } else { f_run1Z = 1; no_runZ = cur_time; sbros = cur_time; f_sbros = 1; sped_Zt = uskor; sped_Z = 0; // для пропуска 1го тика } //Снимаем напряжение с катушек двигателя X if (f_run1X && cur_time - no_runX >= 1000)// закончилось ли время { f_run1X = 0; PORTB &= 0xF0; } //Снимаем напряжение с катушек двигателя Z if (f_run1Z && cur_time - no_runZ >= 1000)// закончилось ли время { f_run1Z = 0; PORTD &= 0xF; } }Добрый вечер. Спасибо, сейчас буду проверять. Я тут немного со схемой повозился, 1 светодиод повесил на 14 пин, 2 светодиод на 15 пин, а на 16 пин прицепил пищалку(при навигации по меню удобно). Можно добавить в скетч?
void Beep() //короткий звук, переключение шторы { tone(ton,500,500); delay(200); noTone(ton); } void Beep_long() //длинный звук, вход и выход из режима калибровки "0" { tone(ton,200,1000); delay(200); noTone(ton); }Проверил скетч...
Со второй шторой всё получилось хорошо, методом тыка настроил высоту - 27500. Ездит хорошо. Полное закрытие или открытие занимает 55 секунд. Немножко не понял в режиме калибровки....как только в него входишь, штору сразу затягивает в барабан, кнопками UP и DOWN возвращаешь на нужное место. С моргающим светодиодом прикольно!
С первой шторой не получится настроить, потому что она должна работать в обратном порядке...моторы стоят не симметрично, здесь нужно инверсию делать.
Вот сделал инверсию попробуйте. Поповоду скорости в стр.72 - StartTimer1(Time_Closk, 2000); можете поиграться с числом, сейчас стоит 2 мс. на меньшем значении у меня стабильно не работает, а у Вас может и будет. По поводу калибровки: при первом входе он сам движется или после установки, при втором заходе тоже?
//********** (РЕЖИМ 1-ШАГ) Крутим с помощью сдвига --рабочая - крутит туда сюда без потери шагов - ускоряет - отключает катушки после бездействия //PORTB - 8, 9, 10, 11 - Шаговик. && 12-кнопка Menu \ 13-Светодиод 1й штор. //PORTD - 4, 5, 6, 7 - Шаговик. && 2-кнопка UP \ 3-кнопка DOWN // А0-Светодиод 2й штор.. #include <CyberLib.h> #define uskor 2 //Задаем ускорение //Здесь устанавливаем максимальное кол. шагов для штор #define max_Sht1 5000 #define max_Sht2 5000 byte n1 = 1;// Сдвигаем 1 бит byte n3 = 0x10; bool f_timX = 0; bool f_timZ = 0; byte sped_Xt = uskor;//Начальная скорость byte sped_X = 0; //Ускорение byte sped_Zt = uskor;//Начальная скорость byte sped_Z = 0; //Ускорение bool f_run1X = 0;//Сброс после остановки 2 переменные. //bool f_run1X = 0; unsigned long no_runX; //Переменная для прошедшего периода bool f_run1Z = 0;//Сброс после остановки 2 переменные. //bool f_run1Z = 0; unsigned long no_runZ; //Переменная для прошедшего периода // Переменные для кн.Menu bool kn_menu; bool f_menu; bool f_Mpush; bool f_Md; uint8_t Menu = 1; uint8_t temp_Menu; bool kalib; unsigned long menu_dreb; unsigned long menu_klik; // Переменные для кн.Up bool kn_Up; bool f_Up; bool state_Up; bool _UP; uint32_t Up_dreb; // Переменные для кн.Down bool kn_Down; bool f_Down; bool state_Down; bool _Down; uint32_t Down_dreb; //сбрасываем UP\Down uint32_t sbros; bool f_sbros; uint32_t cur_time;//Миллис читаем один раз uint32_t blink_time;//Мигаем в режиме калибровки int Shtora1 = 50;// количество шагов для полного закрытия шторы 1; int Shtora2 = 34;// количество шагов для полного закрытия шторы 2 void setup() { // DDRB пин, 8,9,10,11 - Шаговик, pin 12- вход, 13- Выход DDRB = DDRB | B00101111; // pin 8,9,10,11,13 - выход в 0 а входы pin 12, - 0 PORTB = B00000000; // DDRD, подключенный к двигателю pin 4,5,6,7 как выход,pin2,3 Выход DDRD = DDRD | B11110000; // pin 4,5,6,7 - выход в 0 а входы pin 2,3 - 0 PORTD = B00000000;//; D14_Out; // Led_2 D14_Low; //Serial.begin(9600); // Инициализировать TIMER1 StartTimer1(Time_Closk, 2000); } void Time_Closk() // Функция прерывания таймера { f_timX = 1; f_timZ = 1; } //Функция вращения dvigatel 1 void RunX (bool perem_X) { f_timX = 0; if (perem_X) { n1 = (n1 >> 1) | (n1 << 3); //Сдвигаем --Shtora1; } else { n1 = (n1 << 1) | (n1 >> 3); //Сдвигаем ++Shtora1; } n1 = 0x0F & n1; //Маскируем кнопки PORTB = (PORTB & 0xF0) | n1; //Очищаем Младшие биты и пишем туда n1 } //Функция dvigatel 3 void RunZ (bool perem_Z) { f_timZ = 0; if (perem_Z) { n3 = (n3 >> 1) | (n3 << 3); //Сдвигаем --Shtora2; } else { n3 = (n3 << 1) | (n3 >> 3); //Сдвигаем ++Shtora2; } n3 = 0xF0 & n3;//Маскируем PORTD = (PORTD & 0xF) | n3; //Очищаем старшие биты и пишем туда n3 } void loop() { cur_time = millis(); ///////////////////Проверка кнопки МЕНЮ - АНТИДРЕБЕЗГ if (D12_Read && !f_menu) { menu_dreb = cur_time; f_menu = 1; } if (!D12_Read) { kn_menu = 0; f_menu = 0; } if (f_menu && cur_time - menu_dreb >= 20) { kn_menu = 1; if (!f_Mpush) { menu_klik = cur_time; f_Mpush = 1; } } if (f_Mpush && !kn_menu && cur_time - menu_klik < 500) { if (_UP || _Down) { _UP = 0; _Down = 0; } else Menu++; // Меняем if (Menu > 3) Menu = 1; f_Mpush = 0; } else if (f_Mpush && !kn_menu && cur_time - menu_klik > 500) { kalib = !kalib; // Включаем калибровку f_Mpush = 0; } ///////////////////////Проверка кнопки UP - АНТИДРЕБЕЗГ if (D2_Read != f_Up) { //Если сигнал изменился f_Up = !f_Up; Up_dreb = cur_time; } if (kn_Up == D2_Read && cur_time - Up_dreb > 20) kn_Up = !D2_Read; // Было нажатие if (kn_Up && !state_Up) { if (_UP || _Down) { _UP = 0; _Down = 0; state_Up = 1; } else { _UP = !_UP; // Меняем значение state_Up = 1; } } if (!kn_Up)state_Up = 0; // Отпустили ///////////////////////Проверка кнопки DOWN - АНТИДРЕБЕЗГ if (D3_Read != f_Down) { //Если сигнал изменился f_Down = !f_Down; Down_dreb = cur_time; } if (kn_Down == D3_Read && cur_time - Down_dreb > 20) kn_Down = !D3_Read; // Было нажатие if (kn_Down && !state_Down) { if (_UP || _Down) { _UP = 0; _Down = 0; state_Down = 1; } else { _Down = !_Down; // Меняем значение state_Down = 1; } } if (!kn_Down)state_Down = 0; // Отпустили //////////////////////// С кнопками закончили продолжаем логику if (!kalib) { if (Menu != temp_Menu) { temp_Menu = Menu; switch (Menu) { case 1: D13_High; D14_Low; break; case 2: D13_Low; D14_High; break; case 3: D13_High; D14_High; break; } } } else { if (cur_time - blink_time >= 300) { blink_time = cur_time; switch (Menu) { case 1: D13_Inv; D14_Low; break; case 2: D13_Low; D14_Inv; break; case 3: D13_Inv; D14_Inv; break; } } } /////////////////////////// Запуск 1го двигателя если " perem_X != 0 " if (f_timX) { if (_UP || _Down) { if (Menu != 2) { if (!sped_X) { if (!kalib) { //Калибровка отк. if (_UP && Shtora1 < max_Sht1) {//3592 RunX(0); } if (_Down && Shtora1 > 0) { RunX(1); } } else { //Калибровка вкл. if (_UP) { Shtora1 = 0; RunX(0); } if (_Down) { Shtora1 = 1; RunX(1); } } } else if (sped_Xt > 0) { --sped_Xt; sped_X = sped_Xt; f_timX = 0; } else { --sped_X; f_timX = 0; } } }//// } else { f_run1X = 1; no_runX = cur_time; sbros = cur_time; f_sbros = 1; sped_Xt = uskor; sped_X = 0; // для пропуска 1го тика } /////////////////Запуск 3го двигателя если " perem_Z != 0 " //if (!kalib) { if (f_timZ) { if (_UP || _Down) { if (Menu != 1) { if (!sped_Z) { if (!kalib)//Калибровка отк. { if (_Down && Shtora2 < max_Sht2) {//3475 RunZ(0); } if (_UP && Shtora2 > 0) { RunZ(1); } } else {//Калибровка Вкл. if (_UP) { Shtora2 = 0; RunZ(0); } if (_Down) { Shtora2 = 1; RunZ(1); } } } else if (sped_Zt > 0) { --sped_Zt; sped_Z = sped_Zt; f_timZ = 0; } } else { --sped_Z; f_timZ = 0; } }//// } else { f_run1Z = 1; no_runZ = cur_time; sbros = cur_time; f_sbros = 1; sped_Zt = uskor; sped_Z = 0; // для пропуска 1го тика } //Снимаем напряжение с катушек двигателя X if (f_run1X && cur_time - no_runX >= 1000)// закончилось ли время { f_run1X = 0; PORTB &= 0xF0; } //Снимаем напряжение с катушек двигателя Z if (f_run1Z && cur_time - no_runZ >= 1000)// закончилось ли время { f_run1Z = 0; PORTD &= 0xF; } }При первом входе точно движется, сейчас проверю еще пару раз.
Вот сделал инверсию попробуйте. Поповоду скорости в стр.72 - StartTimer1(Time_Closk, 2000); можете поиграться с числом, сейчас стоит 2 мс. на меньшем значении у меня стабильно не работает, а у Вас может и будет. По поводу калибровки: при первом входе он сам движется или после установки, при втором заходе тоже?
Скетч с инверсией проверил - с первой шторой: нажимаешь кнопку DOWN штора едет вверх, UP - вниз.
Со второй шторой тоже самое.
В режиме калибровки первая штора при нажатии DOWN едет вверх, UP-вниз. Вторая штора DOWN -вниз, UP-вверх.
Еще одна особенность появилась....кнопки UP и DOWN срабатывают со второго нажатия.
P/S похоже я Вас ввожу в заблуждение....первая штора пины:8 9 10 11, вторая штора пины:4 5 6 7
Т.е. получается, что до инверсии вторая штора работала правильно.
По поводу проблемы с калибровкой, у себя (на живой плате и в симуляторе) не заметил. Вот проверяйте с инверсией
//********** (РЕЖИМ 1-ШАГ) Крутим с помощью сдвига --рабочая - крутит туда сюда без потери шагов - ускоряет - отключает катушки после бездействия //PORTB - 8, 9, 10, 11 - Шаговик. && 12-кнопка Menu \ 13-Светодиод 1й штор. //PORTD - 4, 5, 6, 7 - Шаговик. && 2-кнопка UP \ 3-кнопка DOWN // А0-Светодиод 2й штор.. #include <CyberLib.h> #define uskor 3 //Задаем ускорение //Здесь устанавливаем максимальное кол. шагов для штор #define max_Sht1 2500 #define max_Sht2 2750 byte n1 = 1;// Сдвигаем 1 бит byte n3 = 0x10; bool f_timX = 0; bool f_timZ = 0; byte sped_Xt = uskor;//Начальная скорость byte sped_X = 0; //Ускорение byte sped_Zt = uskor;//Начальная скорость byte sped_Z = 0; //Ускорение bool f_run1X = 0;//Сброс после остановки 2 переменные. unsigned long no_runX; //Переменная для прошедшего периода bool f_run1Z = 0;//Сброс после остановки 2 переменные. unsigned long no_runZ; //Переменная для прошедшего периода // Переменные для кн.Menu bool kn_menu; bool f_menu; bool f_Mpush; bool f_Md; uint8_t Menu = 1; uint8_t temp_Menu; bool kalib; unsigned long menu_dreb; unsigned long menu_klik; // Переменные для кн.Up bool kn_Up; bool f_Up; bool state_Up; bool _UP; uint32_t Up_dreb; // Переменные для кн.Down bool kn_Down; bool f_Down; bool state_Down; bool _Down; uint32_t Down_dreb; //сбрасываем UP\Down bool f_sbrosZ = 1; bool f_sbrosX = 1; uint32_t cur_time;//Миллис читаем один раз uint32_t blink_time;//Мигаем в режиме калибровки int Shtora1; int Shtora2; void setup() { // DDRB пин, 8,9,10,11 - Шаговик, pin 12- вход, 13- Выход DDRB = DDRB | B00101111; // pin 8,9,10,11,13 - выход в 0 а входы pin 12, - 0 PORTB = B00000000; // DDRD, подключенный к двигателю pin 4,5,6,7 как выход,pin2,3 Выход DDRD = DDRD | B11110000; // pin 4,5,6,7 - выход в 0 а входы pin 2,3 - 0 PORTD = B00000000;//; D14_Out; // Led_2 D14_Low; //Serial.begin(9600); // Инициализировать TIMER1 StartTimer1(Time_Closk, 2000); } void Time_Closk() // Функция прерывания таймера { f_timX = 1; f_timZ = 1; } //Функция вращения dvigatel 1 void RunX (bool perem_X) { f_sbrosX = 0; f_timX = 0; if (perem_X) { n1 = (n1 >> 1) | (n1 << 3); //Сдвигаем --Shtora1; } else { n1 = (n1 << 1) | (n1 >> 3); //Сдвигаем ++Shtora1; } n1 = 0x0F & n1; //Маскируем кнопки PORTB = (PORTB & 0xF0) | n1; //Очищаем Младшие биты и пишем туда n1 } //Функция dvigatel 3 void RunZ (bool perem_Z) { f_sbrosZ = 0; f_timZ = 0; if (perem_Z) { n3 = (n3 >> 1) | (n3 << 3); //Сдвигаем --Shtora2; } else { n3 = (n3 << 1) | (n3 >> 3); //Сдвигаем ++Shtora2; } n3 = 0xF0 & n3;//Маскируем PORTD = (PORTD & 0xF) | n3; //Очищаем старшие биты и пишем туда n3 } void loop() { cur_time = millis(); ///////////////////Проверка кнопки МЕНЮ - АНТИДРЕБЕЗГ if (D12_Read && !f_menu) { menu_dreb = cur_time; f_menu = 1; } if (!D12_Read) { kn_menu = 0; f_menu = 0; } if (f_menu && cur_time - menu_dreb >= 20) { kn_menu = 1; if (!f_Mpush) { menu_klik = cur_time; f_Mpush = 1; } } //Был клик if (f_Mpush && !kn_menu && cur_time - menu_klik < 1000) { if (_UP || _Down) { _UP = 0; _Down = 0; } else Menu++; // Меняем if (Menu > 3) Menu = 1; f_Mpush = 0; } //Было нажатие else if (f_Mpush && !kn_menu && cur_time - menu_klik > 1000) { kalib = !kalib; // Включаем калибровку f_Mpush = 0; } ///////////////////////Проверка кнопки UP - АНТИДРЕБЕЗГ if (D2_Read != f_Up) { //Если сигнал изменился f_Up = !f_Up; Up_dreb = cur_time; } if (kn_Up == D2_Read && cur_time - Up_dreb > 20) kn_Up = !D2_Read; // Было нажатие if (kn_Up && !state_Up) { if (_UP || _Down) { _UP = 0; _Down = 0; state_Up = 1; } else { _UP = !_UP; // Меняем значение state_Up = 1; } } if (!kn_Up)state_Up = 0; // Отпустили ///////////////////////Проверка кнопки DOWN - АНТИДРЕБЕЗГ if (D3_Read != f_Down) { //Если сигнал изменился f_Down = !f_Down; Down_dreb = cur_time; } if (kn_Down == D3_Read && cur_time - Down_dreb > 20) kn_Down = !D3_Read; // Было нажатие if (kn_Down && !state_Down) { if (_UP || _Down) { _UP = 0; _Down = 0; state_Down = 1; } else { _Down = !_Down; // Меняем значение state_Down = 1; } } if (!kn_Down)state_Down = 0; // Отпустили //////////////////////// С кнопками закончили продолжаем логику if (!kalib) { if (Menu != temp_Menu) { temp_Menu = Menu; switch (Menu) { case 1: D13_High; D14_Low; break; case 2: D13_Low; D14_High; break; case 3: D13_High; D14_High; break; } } } else { if (cur_time - blink_time >= 300) { blink_time = cur_time; switch (Menu) { case 1: D13_Inv; D14_Low; break; case 2: D13_Low; D14_Inv; break; case 3: D13_Inv; D14_Inv; break; } } } /////////////////////////// Запуск 1го двигателя если " perem_X != 0 " if (f_timX) { if (_UP || _Down) { if (Menu != 2) { if (!sped_X) { if (!kalib) { //Калибровка отк. if (_Down && Shtora1 < max_Sht1) { RunX(0); } if (_UP && Shtora1 > 0) { RunX(1); } } else { //Калибровка вкл. if (_Down) { Shtora1 = 0; RunX(0); } if (_UP) { Shtora1 = 1; RunX(1); } } //Три поверки для разгона if (sped_Xt > 0) { --sped_Xt; sped_X = sped_Xt; // f_timX = 0; } } else { --sped_X; f_timX = 0; } } }//// else { sped_Xt = uskor; sped_X = 0; } } else { //Для снятия напряжения f_run1X = 1; no_runX = cur_time; } /////////////////Запуск 3го двигателя если " perem_Z != 0 " if (f_timZ) { if (_UP || _Down) { if (Menu != 1) { if (!sped_Z) { if (!kalib)//Калибровка отк. { if (_UP && Shtora2 < max_Sht2) { RunZ(0); } if (_Down && Shtora2 > 0) { RunZ(1); } } else {//Калибровка Вкл. if (_UP) { Shtora2 = 0; RunZ(0); } if (_Down) { Shtora2 = 1; RunZ(1); } } //Три поверки для разгона if (sped_Zt > 0) { --sped_Zt; sped_Z = sped_Zt; f_timZ = 0; } } else { --sped_Z; f_timZ = 0; } } }//// else { sped_Zt = uskor; sped_Z = 0; } } else { //Для снятия напряжения f_run1Z = 1; no_runZ = cur_time; } //Возврат по достижению конечной точки if (f_sbrosZ && f_sbrosX) { _UP = 0; _Down = 0; } //Снимаем напряжение с катушек двигателя X if (f_run1X && cur_time - no_runX >= 1000) { f_run1X = 0; PORTB &= 0xF0; f_sbrosX = 1; } //Снимаем напряжение с катушек двигателя Z if (f_run1Z && cur_time - no_runZ >= 1000) { f_run1Z = 0; PORTD &= 0xF; f_sbrosZ = 1; } }Проверил новый скетч.
В режиме калибровки всё отлично! шторы ездят правильно.
В рабочем режиме вторая штора работает, а с первой шторой происходит следущее:
1. При нажатии DOWN штора стоит.
2. При нажатии UP штора заматывается в барабан.
3. Если сначала в режиме калибровки штору опустить полностью и перейти в рабочий режим, то всё работает как надо.
P.S. Погонял шторы одновременно...когда подогнал высоту, все заработало как и хотелось.
Получается, что сначала нужно провести калибровку, а именно опустить шторы в режиме калибровки до нужного положения, выйти из режима калибровки и всё будет работать. Тогда имеет смысл запретить нажатие кнопок UP и DOWN если калибровка не была проведена, это будет один раз при первом запуске, потом когда положения штор и флаг калибровки(шторы уже калибровались) будут храниться в энергонезависимой памяти, разрешить нажатие кнопок.
34 стр. (kalib) присвойте 1, тоесть (bool kalib = 1;) тогда при запуске\перезапуске сразу будет включена калибровка и чтобы выйти изнеё нужно длинное нажатие
34 стр. (kalib) присвойте 1, тоесть (bool kalib = 1;) тогда при запуске\перезапуске сразу будет включена калибровка и чтобы выйти изнеё нужно длинное нажатие
Понял, а можете на 16 пин повесить пищалку? Я пробовал, но что-то не получается. Только для кнопки меню, на короткое нажатие - короткий сигнал, на длинное - длинный сигнал, ну и тон может отличаться.
Канешно могу, но мы же с Вами договаривались вместе писать код. Общую логику я вывел а такие дополнения подключайтесь и Вы!
Канешно могу, но мы же с Вами договаривались вместе писать код. Общую логику я вывел а такие дополнения подключайтесь и Вы!
Я пробовал вот так:
void Beep() //короткий звук, переключение шторы { tone(ton,500,500); delay(200); noTone(ton); } void Beep_long() //длинный звук, вход и выход из режима калибровки "0" { tone(ton,200,1000); delay(200); noTone(ton); }И вот здесь указал функцию:
//Был клик if (f_Mpush && !kn_menu && cur_time - menu_klik < 1000) { Beep(); if (_UP || _Down) { _UP = 0; _Down = 0; } else Menu++; // Меняем if (Menu > 3) Menu = 1; f_Mpush = 0; } //Было нажатие else if (f_Mpush && !kn_menu && cur_time - menu_klik > 1000) { Beep_long(); kalib = !kalib; // Включаем калибровку f_Mpush = 0; }Но так работать не хочет....где я ошибаюсь?
Хотя если по мне так надобности в пищалке я не вижу потому что кнопка проверяется после отпукания - был клик или нажатие. Светодиоды прекрасно все показывают. При любом писке Вы все равно смотрите на диоды - а что же я включил.
Хотя если по мне так надобности в пищалке я не вижу потому что кнопка проверяется после отпукания - был клик или нажатие. Светодиоды прекрасно все показывают. При любом писке Вы все равно смотрите на диоды - а что же я включил.
Согласен, но всё же....привыкли уже.
Я так думаю ошибка как всегда в делеях?
Если пин ton Вы настроили как ВЫХОД, то почти угадали. А еще в библиотеке CyberLib есть встроеная функция beep, можно почитать и вызывать ее
/Был клик if (f_Mpush && !kn_menu && cur_time - menu_klik < 1000) { if (_UP || _Down) { _UP = 0; _Down = 0; } else Menu++, Beep(); // Меняем if (Menu > 3) Menu = 1; f_Mpush = 0; } //Было нажатие else if (f_Mpush && !kn_menu && cur_time - menu_klik > 1000) { Beep_long(); kalib = !kalib; // Включаем калибровку f_Mpush = 0; }Заработало!
Теперь осталось сохранять позиции штор в память. Такая реализация как у меня была подойдет?
Еще нужно как то высчитывать оставшееся количество шагов до нужной позиции и сохранять результат калибровки....после отключения/включения питания.
Я по-поводу калибровки хочу спросить...когда мы даем питание на плату, как узнать, что калибровка уже проводилась и в ячейках записано значения положения штор? А если, к примеру, хранить в отдельной ячейке 1 - если калибровка проводилась и 0 - если не проводилась. И если 1, то считать значения из ячеек.
Вопрос: в каком месте скетча сделать запись того, что калибровка провелась?
Чтение и запись значений сделал вот так:
#include <EEPROM.h> --------------------------------------------------------------------- // чтение int EEPROM_int_read(int addr) { byte raw[2]; for(byte i = 0; i < 2; i++) raw[i] = EEPROM.read(addr+i); int &num = (int&)raw; return num; } // запись void EEPROM_int_write(int addr, int num) { if (EEPROM_int_read(addr)!= num){//если сохраняемое отличается byte raw[2]; (int&)raw = num; for(byte i = 0; i < 2; i++) EEPROM.write(addr+i, raw[i]); } } ------------------------------------------------------------------------ void setup(){ if (EEPROM_int_read(4)!=1) { Shtora1=28900; Shtora2=27500; } else { Shtora1 = EEPROM_int_read(0); Shtora2 = EEPROM_int_read(2); } } ---------------------------------------------------------------------- void loop(){ //Снимаем напряжение с катушек двигателя X if (f_run1X && cur_time - no_runX >= 1000) { f_run1X = 0; PORTB &= 0xF0; f_sbrosX = 1; if (EEPROM_int_read(0)!=Shtora1) { EEPROM_int_write(0, Shtora1); // адрес 0 (+2 байта) } } //Снимаем напряжение с катушек двигателя Z if (f_run1Z && cur_time - no_runZ >= 1000) { f_run1Z = 0; PORTD &= 0xF; f_sbrosZ = 1; if (EEPROM_int_read(2)!=Shtora2) { EEPROM_int_write(2, Shtora2); // адрес 0 (+2 байта) } } }Поповоду калибровки: Глобальная калибровка должна проводиться один раз после перезаписи Ардуино, Это Вы должны знать и без записи в память. Представим что вы провели калибровку и в памяти записали 1, после этого решили обновить программу а у Вас в памяти записано что калибровку проводить не надо, хотя по факту ее надо провести. Так что я не вижу как указать програме что она перепрошыта и нужно калибровать. А поточные - если будут пропуски двигателя и нужно будет подкоректировать штору то Вы будете сами видеть нужно или нет. А вот записать полжение шторы после ее движения - это можно. После перезапуска программа просто востановит положение штор.
#include <EEPROM.h> --------------------------------------------------------------------- // чтение int EEPROM_int_read(int addr) { byte raw[2]; for(byte i = 0; i < 2; i++) raw[i] = EEPROM.read(addr+i); int &num = (int&)raw; return num; } // запись void EEPROM_int_write(int addr, int num) { if (EEPROM_int_read(addr)!= num){//если сохраняемое отличается byte raw[2]; (int&)raw = num; for(byte i = 0; i < 2; i++) EEPROM.write(addr+i, raw[i]); } } ------------------------------------------------------------------------ void setup(){ Shtora1 = EEPROM_int_read(0); Shtora2 = EEPROM_int_read(2); } ---------------------------------------------------------------------- void loop(){ //Снимаем напряжение с катушек двигателя X if (f_run1X && cur_time - no_runX >= 1000) { f_run1X = 0; PORTB &= 0xF0; f_sbrosX = 1; if (EEPROM_int_read(0)!=Shtora1) { EEPROM_int_write(0, Shtora1); // адрес 0 (+2 байта) } } //Снимаем напряжение с катушек двигателя Z if (f_run1Z && cur_time - no_runZ >= 1000) { f_run1Z = 0; PORTD &= 0xF; f_sbrosZ = 1; if (EEPROM_int_read(2)!=Shtora2) { EEPROM_int_write(2, Shtora2); // адрес 0 (+2 байта) } } }А если для перевода в режим калибровке включить её с нажатыми кнопками или в сетапе считывать значение определённой ячейки. если там скажем 0xff или 0x00 то считаем что калибровки нет.
Я тоже об этом думал и не нашел решения, только появилось еще больше вопросов, поэтому согласен с Вами. Сейчас залью скетч и проверю. Можно Вас попросить, так сказать "на пальцах" объяснить мне, что означают все эти PORTB &= 0xF0, PORTD &= 0xF, n3 = 0xF0 & n3;//Маскируем PORTD = (PORTD & 0xF) | n3; //Очищаем старшие биты и пишем туда n3, DDRB = DDRB | B00101111;, PORTB = B00000000;, DDRD = DDRD | B11110000;,
Если в остальном еще можно разобраться, то это для меня темный лес...
Похоже действительно, запись о калибровке не нужна. Сейчас проверил, ставил шторы в разных положениях и отключал питание, после включения все работает как надо, шторы в крайних положениях останавливаются.
А если для перевода в режим калибровке включить её с нажатыми кнопками или в сетапе считывать значение определённой ячейки. если там скажем 0xff или 0x00 то считаем что калибровки нет.
Установить или прочитать это не проблема, Проблема состоит в ее ипользовании - выше я описал.
ИМХО без наличия ООС точное определение положения шторы невозможно. Вот если бы концевики. или по току моторчика определять крайние положения... Но это так - мысли вслух...
Было бы интересно посмотреть видео с работой устройства когда будет всё готово.
ИМХО без наличия ООС точное определение положения шторы невозможно. Вот если бы концевики. или по току моторчика определять крайние положения... Но это так - мысли вслух...
Было бы интересно посмотреть видео с работой устройства когда будет всё готово.
Видео есть в этой теме http://arduino.ru/forum/proekty/rulonnye-shtory-na-arduino
Это еще до переделки, у меня моторы не хотели работать одновременно, а по-одному работали практически так же, только чуть медленнее. Сейчас вообще всё работает изумительно!
Может завтра пересниму....главное не забыть телефон горизонтально держать :)
На пальцах не получится да и не все сразу как пример можете посмотреть
http://arduino.net.ua/Arduino_articles/Opisanie%20jazyka%20Arduino%20na%20russkom%20jazyke/Manipuljacii%20s%20portami/
http://cxem.net/arduino/arduino6.php
На пальцах не получится да и не все сразу как пример можете посмотреть
http://arduino.net.ua/Arduino_articles/Opisanie%20jazyka%20Arduino%20na%20russkom%20jazyke/Manipuljacii%20s%20portami/
http://cxem.net/arduino/arduino6.php
Спасибо. Я это уже читал, похоже пока не пощупаешь фиг научишься....
На пальцах не получится да и не все сразу как пример можете посмотреть
Я Вам еще не сильно надоел?
Посмотрел - с учтётом монументальности конструкции - склоняюсь ко мнению что дрейф будет минимальным и ООС можно принебречь.
PS. Очень понравилось качество изготовления.
Посмотрел - с учтётом монументальности конструкции - склоняюсь ко мнению что дрейф будет минимальным и ООС можно принебречь.
PS. Очень понравилось качество изготовления.
Спасибо! Старался, чтобы выглядело не очень колхозно....еще бы моторчики спрятать под колпачком, но для этого 3д принтер бы.....
Да тоже посмотрел - сделано акуратно!
Да тоже посмотрел - сделано акуратно!
Спасибо! Можно Вас еще подаставать?
Ну если смогу то помогу.
Ну если смогу то помогу.
Сначала хочу Вас поблагодарить! Без Вашей помощи был бы у меня коряво работающий скетч....а сейчас я просто ненарадуюсь :) Спасибо огромное!
Ну а теперь .....у меня в зале окно эркер....
Там установлены 3 шторки. Вас не затруднит переделать этот скетч под Мегу на 3 мотора?
Особенности: на 1 и 3 шторах моторы установлены так же как и в этом скетче, а у 2-ой шторы так же как у 3-ей.
Воистину человеческой наглости нет предела, но без Вашей помощи я еще полгода буду учиться моргать светодиодом, а шторы хочется закончить уже сейчас.
Ладно попробую, только Меги у меня нет испытувать будете Вы
Ладно попробую, только Меги у меня нет испытувать будете Вы
Я завтра попробую переделать часть скетча по аналогии, я так понимаю нужно добавить все как для Z только с Y? Плюс меню увеличить на 1, добавить светодиод.....ну а моторы вращать уже мне не по силам. А еще нужно с пинами определиться...
Кстати, никогда не игрался с шаговыми двигателями, но почитав в интернете возникла следующая мысль - правильно ли я понял, что если взять два двигателя и подключить их парраллельно но с распиновкой у одного в порядке 1-2-3-4 а у другого 4-3-2-1 то мы получим одновременно работающие двигатели крутящиеся в противоположные стороны?
Если это так, то можно было бы взять 3 мосфета, и ими включать и выключать нужные двигатели, подключенные параллельно, а всё управление останется на 4х выводах. ведь ситуация при которой одна штора опускается, а другая поднимается - не предусмотрена ТЗ?
Кстати, никогда не игрался с шаговыми двигателями, но почитав в интернете возникла следующая мысль - правильно ли я понял, что если взять два двигателя и подключить их парраллельно но с распиновкой у одного в порядке 1-2-3-4 а у другого 4-3-2-1 то мы получим одновременно работающие двигатели крутящиеся в противоположные стороны?
Если это так, то можно было бы взять 3 мосфета, и ими включать и выключать нужные двигатели, подключенные параллельно, а всё управление останется на 4х выводах. ведь ситуация при которой одна штора опускается, а другая поднимается - не предусмотрена ТЗ?
На мой взгляд в этом есть зерно. Их не обезтельно включать навстречу, пусть крутят и паралельно.
Я завтра попробую переделать часть скетча по аналогии, я так понимаю нужно добавить все как для Z только с Y? Плюс меню увеличить на 1, добавить светодиод.....ну а моторы вращать уже мне не по силам. А еще нужно с пинами определиться...
Кнопки: 2 - UP, 3 - DOWN, 4 - MENU
Светодиоды: 5 - Led1, 6 - Led2, 7 - Led3
Пищалка: 8 - Ton
Моторы: PORTA, PORTC, PORTL
Так пойдет? Я просто не знаю, может один порт управлять двумя моторами.
Я еще ничего не подключал, поэтому пока не критично.
И вот изменил скетч, поправьте если что не так. (что не смог сделать я отметил /////////////////////////)
//********** (РЕЖИМ 1-ШАГ) Крутим с помощью сдвига --рабочая - крутит туда сюда без потери шагов - ускоряет - отключает катушки после бездействия //PORTB - 8, 9, 10, 11 - Шаговик. && 12-кнопка Menu \ 13-Светодиод 1й штор. //PORTD - 4, 5, 6, 7 - Шаговик. && 2-кнопка UP \ 3-кнопка DOWN // А0-Светодиод 2й штор.. #include <EEPROM.h> #include <CyberLib.h> #define uskor 3 //Задаем ускорение //Здесь устанавливаем максимальное кол. шагов для штор #define max_Sht1 28900 #define max_Sht2 30500 #define max_Sht3 28900 byte n1 = 1;// Сдвигаем 1 бит byte n3 = 0x10; bool f_timX = 0; bool f_timY = 0; bool f_timZ = 0; byte sped_Xt = uskor;//Начальная скорость byte sped_X = 0; //Ускорение byte sped_Yt = uskor;//Начальная скорость byte sped_Y = 0; //Ускорение byte sped_Zt = uskor;//Начальная скорость byte sped_Z = 0; //Ускорение bool f_run1X = 0;//Сброс после остановки 2 переменные. unsigned long no_runX; //Переменная для прошедшего периода bool f_run1Y = 0;//Сброс после остановки 2 переменные. unsigned long no_runY; //Переменная для прошедшего периода bool f_run1Z = 0;//Сброс после остановки 2 переменные. unsigned long no_runZ; //Переменная для прошедшего периода // Переменные для кн.Menu bool kn_menu; bool f_menu; bool f_Mpush; bool f_Md; uint8_t Menu = 1; uint8_t temp_Menu; bool kalib; unsigned long menu_dreb; unsigned long menu_klik; // Переменные для кн.Up bool kn_Up; bool f_Up; bool state_Up; bool _UP; uint32_t Up_dreb; // Переменные для кн.Down bool kn_Down; bool f_Down; bool state_Down; bool _Down; uint32_t Down_dreb; //сбрасываем UP\Down bool f_sbrosZ = 1; bool f_sbrosY = 1; bool f_sbrosX = 1; uint32_t cur_time;//Миллис читаем один раз uint32_t blink_time;//Мигаем в режиме калибровки int Shtora1; int Shtora2; int Shtora3; const int ton = 8;//пищалка // чтение int EEPROM_int_read(int addr) { byte raw[2]; for(byte i = 0; i < 2; i++) raw[i] = EEPROM.read(addr+i); int &num = (int&)raw; return num; } // запись void EEPROM_int_write(int addr, int num) { if (EEPROM_int_read(addr)!= num){//если сохраняемое отличается byte raw[2]; (int&)raw = num; for(byte i = 0; i < 2; i++) EEPROM.write(addr+i, raw[i]); } } void setup() { // DDRB пин, 8,9,10,11 - Шаговик, pin 12- вход, 13- Выход ////////////////////////////////////////////////////////////////////// DDRB = DDRB | B00101111; // pin 8,9,10,11,13 - выход в 0 а входы pin 12, - 0 ////////////////////////////////////////////////////////////////////// PORTB = B00000000; // DDRD, подключенный к двигателю pin 4,5,6,7 как выход,pin2,3 Выход ////////////////////////////////////////////////////////////////////// DDRD = DDRD | B11110000; // pin 4,5,6,7 - выход в 0 а входы pin 2,3 - 0 ////////////////////////////////////////////////////////////////////// PORTD = B00000000;//; D2_In; //2-кнопка UP D3_In; //3-кнопка DOWN D4_In; //4-кнопка MENU D5_Out; // Led_1 D5_Low; D6_Out; // Led_2 D6_Low; D7_Out; // Led_3 D7_Low; pinMode(ton,OUTPUT);//пищалка //Serial.begin(9600); // Инициализировать TIMER1 StartTimer1(Time_Closk, 2200); Shtora1 = EEPROM_int_read(0); Shtora2 = EEPROM_int_read(2); Shtora3 = EEPROM_int_read(4); } void Beep() //короткий звук, переключение шторы { tone(ton,500,500); delay(200); noTone(ton); } void Beep_long() //длинный звук, вход и выход из режима калибровки "0" { tone(ton,200,1000); delay(200); noTone(ton); } void Time_Closk() // Функция прерывания таймера { f_timX = 1; f_timY = 1; f_timZ = 1; } //Функция вращения dvigatel 1 void RunX (bool perem_X) { f_sbrosX = 0; f_timX = 0; if (perem_X) { n1 = (n1 >> 1) | (n1 << 3); //Сдвигаем --Shtora1; } else { n1 = (n1 << 1) | (n1 >> 3); //Сдвигаем ++Shtora1; } ///////////////////////////////////////////////////// n1 = 0x0F & n1; //Маскируем кнопки ///////////////////////////////////////////////////// PORTB = (PORTB & 0xF0) | n1; //Очищаем Младшие биты и пишем туда n1 } //Функция dvigatel 2 void RunY (bool perem_Y) { f_sbrosY = 0; f_timY = 0; if (perem_Y) { n3 = (n3 >> 1) | (n3 << 3); //Сдвигаем --Shtora2; } else { n3 = (n3 << 1) | (n3 >> 3); //Сдвигаем ++Shtora2; } /////////////////////////////////////////////////// n3 = 0xF0 & n3;//Маскируем /////////////////////////////////////////////////// PORTD = (PORTD & 0xF) | n3; //Очищаем старшие биты и пишем туда n3 } //Функция dvigatel 3 void RunZ (bool perem_Z) { f_sbrosZ = 0; f_timZ = 0; if (perem_Z) { n3 = (n3 >> 1) | (n3 << 3); //Сдвигаем --Shtora3; } else { n3 = (n3 << 1) | (n3 >> 3); //Сдвигаем ++Shtora3; } ////////////////////////////////////////////////// n3 = 0xF0 & n3;//Маскируем ////////////////////////////////////////////////// PORTD = (PORTD & 0xF) | n3; //Очищаем старшие биты и пишем туда n3 } void loop() { cur_time = millis(); ///////////////////Проверка кнопки МЕНЮ - АНТИДРЕБЕЗГ if (D4_Read && !f_menu) { menu_dreb = cur_time; f_menu = 1; } if (!D4_Read) { kn_menu = 0; f_menu = 0; } if (f_menu && cur_time - menu_dreb >= 20) { kn_menu = 1; if (!f_Mpush) { menu_klik = cur_time; f_Mpush = 1; } } //Был клик if (f_Mpush && !kn_menu && cur_time - menu_klik < 1000) { if (_UP || _Down) { _UP = 0; _Down = 0; } else Menu++, Beep(); // Меняем if (Menu > 4) Menu = 1; f_Mpush = 0; } //Было нажатие else if (f_Mpush && !kn_menu && cur_time - menu_klik > 1000) { Beep_long(); kalib = !kalib; // Включаем калибровку f_Mpush = 0; } ///////////////////////Проверка кнопки UP - АНТИДРЕБЕЗГ if (D2_Read != f_Up) { //Если сигнал изменился f_Up = !f_Up; Up_dreb = cur_time; } if (kn_Up == D2_Read && cur_time - Up_dreb > 20) kn_Up = !D2_Read; // Было нажатие if (kn_Up && !state_Up) { if (_UP || _Down) { _UP = 0; _Down = 0; state_Up = 1; } else { _UP = !_UP; // Меняем значение state_Up = 1; } } if (!kn_Up)state_Up = 0; // Отпустили ///////////////////////Проверка кнопки DOWN - АНТИДРЕБЕЗГ if (D3_Read != f_Down) { //Если сигнал изменился f_Down = !f_Down; Down_dreb = cur_time; } if (kn_Down == D3_Read && cur_time - Down_dreb > 20) kn_Down = !D3_Read; // Было нажатие if (kn_Down && !state_Down) { if (_UP || _Down) { _UP = 0; _Down = 0; state_Down = 1; } else { _Down = !_Down; // Меняем значение state_Down = 1; } } if (!kn_Down)state_Down = 0; // Отпустили //////////////////////// С кнопками закончили продолжаем логику if (!kalib) { if (Menu != temp_Menu) { temp_Menu = Menu; switch (Menu) { case 1: D5_High; D6_Low; D7_Low; break; case 2: D5_Low; D6_High; D7_Low; break; case 3: D5_Low; D6_Low; D7_High; break; case 4: D5_High; D6_High; D7_High; break; } } } else { if (cur_time - blink_time >= 300) { blink_time = cur_time; switch (Menu) { case 1: D5_Inv; D6_Low; D7_Low; break; case 2: D5_Low; D6_Inv; D7_Low; break; case 3: D5_Low; D6_Low; D7_Inv break; case 4: D5_Inv; D6_Inv; D7_Inv break; } } } /////////////////////////// Запуск 1го двигателя если " perem_X != 0 " if (f_timX) { if (_UP || _Down) { if (Menu != 1) { if (!sped_X) { if (!kalib) { //Калибровка отк. if (_Down && Shtora1 < max_Sht1) { RunX(0); } if (_UP && Shtora1 > 0) { RunX(1); } } else { //Калибровка вкл. if (_Down) { Shtora1 = 0; RunX(0); } if (_UP) { Shtora1 = 1; RunX(1); } } //Три поверки для разгона if (sped_Xt > 0) { --sped_Xt; sped_X = sped_Xt; // f_timX = 0; } } else { --sped_X; f_timX = 0; } } }//// else { sped_Xt = uskor; sped_X = 0; } } else { //Для снятия напряжения f_run1X = 1; no_runX = cur_time; } /////////////////Запуск 2го двигателя если " perem_Y != 0 " if (f_timY) { if (_UP || _Down) { if (Menu != 2) { if (!sped_Y) { if (!kalib)//Калибровка отк. { if (_UP && Shtora2 < max_Sht2) { RunY(0); } if (_Down && Shtora2 > 0) { RunY(1); } } else {//Калибровка Вкл. if (_UP) { Shtora2 = 0; RunY(0); } if (_Down) { Shtora2 = 1; RunY(1); } } //Три поверки для разгона if (sped_Yt > 0) { --sped_Yt; sped_Y = sped_Yt; f_timY = 0; } } else { --sped_Y; f_timY = 0; } } }//// else { sped_Yt = uskor; sped_Y = 0; } } else { //Для снятия напряжения f_run1Y = 1; no_runY = cur_time; } /////////////////Запуск 3го двигателя если " perem_Z != 0 " if (f_timZ) { if (_UP || _Down) { if (Menu != 3) { if (!sped_Z) { if (!kalib)//Калибровка отк. { if (_UP && Shtora3 < max_Sht3) { RunZ(0); } if (_Down && Shtora3 > 0) { RunZ(1); } } else {//Калибровка Вкл. if (_UP) { Shtora3 = 0; RunZ(0); } if (_Down) { Shtora3 = 1; RunZ(1); } } //Три поверки для разгона if (sped_Zt > 0) { --sped_Zt; sped_Z = sped_Zt; f_timZ = 0; } } else { --sped_Z; f_timZ = 0; } } }//// else { sped_Zt = uskor; sped_Z = 0; } } else { //Для снятия напряжения f_run1Z = 1; no_runZ = cur_time; } //Возврат по достижению конечной точки if (f_sbrosZ && f_sbrosY && f_sbrosX) { _UP = 0; _Down = 0; } //Снимаем напряжение с катушек двигателя X if (f_run1X && cur_time - no_runX >= 1000) { f_run1X = 0; ////////////////////////////////////////////////////////////// PORTB &= 0xF0; f_sbrosX = 1; if (EEPROM_int_read(0)!=Shtora1) { EEPROM_int_write(0, Shtora1); // адрес 0 (+2 байта) } } //Снимаем напряжение с катушек двигателя Y if (f_run1Y && cur_time - no_runY >= 1000) { f_run1Y = 0; ///////////////////////////////////////////////////////////// PORTD &= 0xF; f_sbrosY = 1; if (EEPROM_int_read(2)!=Shtora2) { EEPROM_int_write(2, Shtora2); // адрес 2 (+2 байта) } } //Снимаем напряжение с катушек двигателя Z if (f_run1Z && cur_time - no_runZ >= 1000) { f_run1Z = 0; /////////////////////////////////////////////////////////// PORTD &= 0xF; f_sbrosZ = 1; if (EEPROM_int_read(4)!=Shtora3) { EEPROM_int_write(4, Shtora3); // адрес 4 (+2 байта) } } }Я просто не знаю, может один порт управлять двумя моторами.
а почему бы и нет? Он же через ULN работает.
Кстати, ИМХО, есть смысл провести эксперимент - подключить два мотора, как я писал выше. Что бы они от одного порта крутились в разные стороны. Тогда будет достаточно 10 лап на 3 кнопки, 3 мотора и 4 вывода управления
Кстати, ИМХО, есть смысл провести эксперимент - подключить два мотора, как я писал выше. Что бы они от одного порта крутились в разные стороны. Тогда будет достаточно 10 лап на 3 кнопки, 3 мотора и 4 вывода управления
Проверил Ваше предположение....верно, можно все три мотора подключить к четырем пинам по схеме 1-2-3-4, причем один мотор подключил 4-3-2-1....нажимаешь кнопку "вправо" крутятся два в право, а один влево и наоборот. Удерживая вращение, снимал перемычку на драйвере (как Вы и сказали типа мосфетом дал команду), нужный мотор останавливался, остальные крутятся.
Получается, что нужно дать команду на вращение и мосфетами выбирать нужный мотор или все сразу. А по мин или макс положению выключать.
Да. Мне кажется что так и код будет проще, и ардуинку подешевле можно использовать.
Да. Мне кажется что так и код будет проще, и ардуинку подешевле можно использовать.
Осталось придумать как считать шаги каждого мотора отдельно, шторы могут находиться в разных положениях, а двигаться нужно к примеру в мах.
Да. Мне кажется что так и код будет проще, и ардуинку подешевле можно использовать.
Осталось придумать как считать шаги каждого мотора отдельно, шторы могут находиться в разных положениях, а двигаться нужно к примеру в мах.
Давайте пока попробуем на Мега, которой у меня нет и испытать не могу
//********** (РЕЖИМ 1-ШАГ) Крутим с помощью сдвига --рабочая - крутит туда сюда без потери шагов - ускоряет - отключает катушки после бездействия //PORTA - к двигателю X (22,23,24,25,) - как выход //PORTC - к двигателю Y,Z (37,36,35,34) (33,32,31,30) как выход // 2, 3, 4 - Кнопки #include <EEPROM.h> #include <CyberLib.h> #define uskor 3 //Задаем ускорение //Здесь устанавливаем максимальное кол. шагов для штор #define max_Sht1 28900 #define max_Sht2 30500 #define max_Sht3 28900 byte n_x = 1;// byte n_y = 1; byte n_z = 0x10; bool f_timX = 0; bool f_timY = 0; bool f_timZ = 0; byte sped_Xt = uskor;//Начальная скорость byte sped_X = 0; //Ускорение byte sped_Yt = uskor;//Начальная скорость byte sped_Y = 0; //Ускорение byte sped_Zt = uskor;//Начальная скорость byte sped_Z = 0; //Ускорение bool f_run1X = 0;//Сброс после остановки 2 переменные. unsigned long no_runX; //Переменная для прошедшего периода bool f_run1Y = 0;//Сброс после остановки 2 переменные. unsigned long no_runY; //Переменная для прошедшего периода bool f_run1Z = 0;//Сброс после остановки 2 переменные. unsigned long no_runZ; //Переменная для прошедшего периода // Переменные для кн.Menu bool kn_menu; bool f_menu; bool f_Mpush; bool f_Md; uint8_t Menu = 1; uint8_t temp_Menu; bool kalib; unsigned long menu_dreb; unsigned long menu_klik; // Переменные для кн.Up bool kn_Up; bool f_Up; bool state_Up; bool _UP; uint32_t Up_dreb; // Переменные для кн.Down bool kn_Down; bool f_Down; bool state_Down; bool _Down; uint32_t Down_dreb; //сбрасываем UP\Down bool f_sbrosZ = 1; bool f_sbrosY = 1; bool f_sbrosX = 1; uint32_t cur_time;//Миллис читаем один раз uint32_t blink_time;//Мигаем в режиме калибровки int Shtora1; int Shtora2; int Shtora3; const int ton = 8;//пищалка void setup() { // DDRA , к двигателю X (22,23,24,25,) - как выход Led, Beep (26,27,28,29) DDRA = 0xFF; //Устанавлюем значение выходов PORTA в 0 PORTA = 0x00; //DDRC к двигателю Y,Z (37,36,35,34) (33,32,31,30) как выход DDRC = DDRC | B11111111; //Устанавлюем значение выходов PORTC в 0 PORTC = B00000000;//x0F; //Serial.begin(9600); // Инициализировать TIMER1 noInterrupts (); // отключить все прерывания TCCR1A = 0; TCCR1B = 0; TCNT1 = 0; OCR1A = 125; // сравнить регистр (скорость!!!(2ms=125 - если медлиннее - УВЕЛИЧУЕМ) TCCR1B |= (1 << WGM12); // Режим СТС TCCR1B |= (1 << CS12); // 256 делитель TIMSK1 |= (1 << OCIE1A ); // включить таймер сравнить прерываний interrupts(); // включить все прерывания D2_In; D3_In; D4_In; D5_Out; D5_Low; D6_Out; D6_Low; D7_Out; D7_Low; D8_Out; D8_Low; } // чтение int EEPROM_int_read(int addr) { byte raw[2]; for (byte i = 0; i < 2; i++) raw[i] = EEPROM.read(addr + i); int &num = (int&)raw; return num; } // запись void EEPROM_int_write(int addr, int num) { if (EEPROM_int_read(addr) != num) { //если сохраняемое отличается byte raw[2]; (int&)raw = num; for (byte i = 0; i < 2; i++) EEPROM.write(addr + i, raw[i]); } } void Beep() //короткий звук, переключение шторы { tone(ton, 500, 500); delay(200); noTone(ton); } void Beep_long() //длинный звук, вход и выход из режима калибровки "0" { tone(ton, 200, 1000); delay(200); noTone(ton); } //Функция 1 dvigatel void RunX (bool perem_X) { f_sbrosX = 0; f_timX = 0; if (perem_X) { n_x = (n_x >> 1) | (n_x << 3); //Сдвигаем --Shtora1; } else { n_x = (n_x << 1) | (n_x >> 3); //Сдвигаем ++Shtora1; } n_x = 0x0F & n_x; //Маскируем кнопки PORTA = (PORTA & 0xF0) | n_x; //Очищаем Младшие биты и пишем туда n_x } //Функция 2 dvigatel void RunY (bool perem_Y) { f_sbrosY = 0; f_timY = 0; if (perem_Y) { n_y = (n_y >> 1) | (n_y << 3); //Сдвигаем --Shtora2; } else { n_y = (n_y << 1) | (n_y >> 3); //Сдвигаем ++Shtora2; } n_y = 0xF & n_y; //Маскируем кнопки PORTC = (PORTC & 0xF0) | n_y; //Очищаем Младшие биты и пишем туда n_y } //Функция 3 dvigatel void RunZ (bool perem_Z) { f_sbrosZ = 0; f_timZ = 0; if (perem_Z) { n_z = (n_z >> 1) | (n_z << 3); //Сдвигаем --Shtora3; } else { n_z = (n_z << 1) | (n_z >> 3); //Сдвигаем ++Shtora3; } n_z = 0xF0 & n_z;//Маскируем PORTC = (PORTC & 0xF) | n_z; //Очищаем старшие биты и пишем туда n_z } ISR (TIMER1_COMPA_vect) // Функция прерывания таймера { f_timX = 1; f_timY = 1; f_timZ = 1; } void loop() { cur_time = millis(); ///////////////////Проверка кнопки МЕНЮ - АНТИДРЕБЕЗГ if (D4_Read && !f_menu) { menu_dreb = cur_time; f_menu = 1; } if (!D4_Read) { kn_menu = 0; f_menu = 0; } if (f_menu && cur_time - menu_dreb >= 20) { kn_menu = 1; if (!f_Mpush) { menu_klik = cur_time; f_Mpush = 1; } } //Был клик if (f_Mpush && !kn_menu && cur_time - menu_klik < 1000) { if (_UP || _Down) { _UP = 0; _Down = 0; } else Menu++, Beep(); // Меняем if (Menu > 4) Menu = 1; f_Mpush = 0; } //Было нажатие else if (f_Mpush && !kn_menu && cur_time - menu_klik > 1000) { Beep_long(); kalib = !kalib; // Включаем калибровку f_Mpush = 0; } ///////////////////////Проверка кнопки UP - АНТИДРЕБЕЗГ if (D2_Read != f_Up) { //Если сигнал изменился f_Up = !f_Up; Up_dreb = cur_time; } if (kn_Up == D2_Read && cur_time - Up_dreb > 20) kn_Up = !D2_Read; // Было нажатие if (kn_Up && !state_Up) { if (_UP || _Down) { _UP = 0; _Down = 0; state_Up = 1; } else { _UP = !_UP; // Меняем значение state_Up = 1; } } if (!kn_Up)state_Up = 0; // Отпустили ///////////////////////Проверка кнопки DOWN - АНТИДРЕБЕЗГ if (D3_Read != f_Down) { //Если сигнал изменился f_Down = !f_Down; Down_dreb = cur_time; } if (kn_Down == D3_Read && cur_time - Down_dreb > 20) kn_Down = !D3_Read; // Было нажатие if (kn_Down && !state_Down) { if (_UP || _Down) { _UP = 0; _Down = 0; state_Down = 1; } else { _Down = !_Down; // Меняем значение state_Down = 1; } } if (!kn_Down)state_Down = 0; // Отпустили //////////////////////// С кнопками закончили продолжаем логику if (!kalib) { if (Menu != temp_Menu) { temp_Menu = Menu; switch (Menu) { case 1: D5_High; D6_Low; D7_Low; break; case 2: D5_Low; D6_High; D7_Low; break; case 3: D5_Low; D6_Low; D7_High; break; case 4: D5_High; D6_High; D7_High; break; } } } else { if (cur_time - blink_time >= 300) { blink_time = cur_time; switch (Menu) { case 1: D5_Inv; D6_Low; D7_Low; break; case 2: D5_Low; D6_Inv; D7_Low; break; case 3: D5_Low; D6_Low; D7_Inv; break; case 4: D5_Inv; D6_Inv; D7_Inv; break; } } } /////////////////////////// Запуск 1го двигателя если if (f_timX) { if (_UP || _Down) { if (Menu == 1 || Menu == 4) { if (!sped_X) { if (!kalib) { //Калибровка отк. if (_Down && Shtora1 < max_Sht1) { RunX(0); } if (_UP && Shtora1 > 0) { RunX(1); } } else { //Калибровка вкл. if (_Down) { Shtora1 = 0; RunX(0); } if (_UP) { Shtora1 = 1; RunX(1); } } //Три поверки для разгона if (sped_Xt > 0) { --sped_Xt; sped_X = sped_Xt; // f_timX = 0; } } else { --sped_X; f_timX = 0; } } }//// else { sped_Xt = uskor; sped_X = 0; } } else { //Для снятия напряжения f_run1X = 1; no_runX = cur_time; } /////////////////Запуск 2го двигателя если if (f_timY) { if (_UP || _Down) { if (Menu == 2 || Menu == 4) { if (!sped_Y) { if (!kalib)//Калибровка отк. { if (_UP && Shtora2 < max_Sht2) { RunY(0); } if (_Down && Shtora2 > 0) { RunY(1); } } else {//Калибровка Вкл. if (_UP) { Shtora2 = 0; RunY(0); } if (_Down) { Shtora2 = 1; RunY(1); } } //Три поверки для разгона if (sped_Yt > 0) { --sped_Yt; sped_Y = sped_Yt; f_timY = 0; } } else { --sped_Y; f_timY = 0; } } }//// else { sped_Yt = uskor; sped_Y = 0; } } else { //Для снятия напряжения f_run1Y = 1; no_runY = cur_time; } /////////////////Запуск 3го двигателя if (f_timZ) { if (_UP || _Down) { if (Menu == 3 || Menu == 4) { if (!sped_Z) { if (!kalib)//Калибровка отк. { if (_UP && Shtora3 < max_Sht3) { RunZ(0); } if (_Down && Shtora3 > 0) { RunZ(1); } } else {//Калибровка Вкл. if (_UP) { Shtora3 = 0; RunZ(0); } if (_Down) { Shtora3 = 1; RunZ(1); } } //Три поверки для разгона if (sped_Zt > 0) { --sped_Zt; sped_Z = sped_Zt; f_timZ = 0; } } else { --sped_Z; f_timZ = 0; } } }//// else { sped_Zt = uskor; sped_Z = 0; } } else { //Для снятия напряжения f_run1Z = 1; no_runZ = cur_time; } //Возврат по достижению конечной точки if (f_sbrosZ && f_sbrosY && f_sbrosX) { _UP = 0; _Down = 0; } ////////////////////// //Снимаем напряжение с катушек двигателя X if (f_run1X && cur_time - no_runX >= 1000) { f_run1X = 0; PORTA &= 0xF0; f_sbrosX = 1; if (EEPROM_int_read(0) != Shtora1) { EEPROM_int_write(0, Shtora1); // адрес 0 (+2 байта) } } //Снимаем напряжение с катушек двигателя Y if (f_run1Y && cur_time - no_runY >= 1000) { f_run1Y = 0; PORTC &= 0xF0; f_sbrosY = 1; if (EEPROM_int_read(2) != Shtora2) { EEPROM_int_write(2, Shtora2); // адрес 2 (+2 байта) } } //Снимаем напряжение с катушек двигателя Z if (f_run1Z && cur_time - no_runZ >= 1000) { f_run1Z = 0; PORTC &= 0xF; f_sbrosZ = 1; if (EEPROM_int_read(4) != Shtora3) { EEPROM_int_write(4, Shtora3); // адрес 4 (+2 байта) } } }Давайте пока попробуем на Мега, которой у меня нет и испытать не могу
Испытывал на столе, моторы разложил как они должны стоять на шторах. Сначала была небольшая путаница, моторы крутились не в те стороны какие нужно....подключал вот так:
Да. Мне кажется что так и код будет проще, и ардуинку подешевле можно использовать.
Вот попробовал - Сказать что код по проще это врядли а на ардуинке да выигруем. Если интересно то вот
//********** (РЕЖИМ 1-ШАГ) Крутим с помощью сдвига --рабочая - крутит туда сюда без потери шагов - ускоряет - отключает катушки после бездействия //PORTB - 8, 9, 10, 11 - Шаговик. && 12-кнопка ; 13 лед Menu1 //PORTD - 4, 5, 6, Выход но транзистор; 7 - лед Menu3 && 2-кнопка UP \ 3-кнопка DOWN (УСЛОВНО!!!) // А0-Светодиод 2й штор (Menu2).. #include <CyberLib.h> #define uskor 3 //Задаем ускорение //Здесь устанавливаем максимальное кол. шагов для штор #define max_Sht1 28900 #define max_Sht2 30500 #define max_Sht3 28900 byte n1 = 1;// Сдвигаем 1 бит bool f_timX = 0; byte sped_Xt = uskor;//Начальная скорость byte sped_X = 0; //Ускорение bool f_run1X = 0;//Сброс после остановки 2 переменные. unsigned long no_runX; //Переменная для прошедшего периода // Переменные для кн.Menu bool kn_menu; bool f_menu; bool f_Mpush; bool f_Md; uint8_t Menu = 1; uint8_t temp_Menu; bool kalib; unsigned long menu_dreb; unsigned long menu_klik; // Переменные для кн.Up bool kn_Up; bool f_Up; bool state_Up; bool _UP; uint32_t Up_dreb; // Переменные для кн.Down bool kn_Down; bool f_Down; bool state_Down; bool _Down; uint32_t Down_dreb; //сбрасываем UP\Down bool f_sbrosX = 1; bool _Mofs1; bool _Mofs2; bool _Mofs3; uint32_t cur_time;//Миллис читаем один раз uint32_t blink_time;//Мигаем в режиме калибровки int Shtora1; int Shtora2; int Shtora3; void setup() { // DDRB пин, 8,9,10,11 - Шаговик, pin 12- вход, 13- Выход DDRB = DDRB | 0B00101111; // pin 8,9,10,11,13 - выход в 0 а входы pin 12, - 0 PORTB = 0B00000000; // DDRD, pin 4,5,6,7 как выход,pin2,3 Выход DDRD = DDRD | 0B11110000; // pin 4,5,6,7 - выход в 0 а входы pin 2,3 - 0 PORTD = PORTD & 0b00001111;//; D14_Out; // Led_2 D14_Low; //Serial.begin(9600); // Инициализировать TIMER1 StartTimer1(Time_Closk, 2000); } void Time_Closk() // Функция прерывания таймера { f_timX = 1; } //Функция вращения dvigatel 1 void RunX (bool perem_X) { f_sbrosX = 0; f_timX = 0; if (perem_X) { n1 = (n1 >> 1) | (n1 << 3); //Сдвигаем } else { n1 = (n1 << 1) | (n1 >> 3); //Сдвигаем } n1 = 0x0F & n1; //Маскируем кнопки PORTB = (PORTB & 0xF0) | n1; //Очищаем Младшие биты и пишем туда n1 switch (Menu) { case 1: if (_Down)Shtora1++; if (_UP)Shtora1--; break; case 2: if (_Down)Shtora2++; if (_UP)Shtora2--; break; case 3: if (_Down)Shtora3++; if (_UP)Shtora3--; break; case 4: if (_Down) { if (_Mofs1)Shtora1++; if (_Mofs2)Shtora2++; if (_Mofs3)Shtora3++; } if (_UP) { if (_Mofs1)Shtora1--; if (_Mofs2)Shtora2--; if (_Mofs3)Shtora3--; } break; } } void loop() { cur_time = millis(); ///////////////////Проверка кнопки МЕНЮ - АНТИДРЕБЕЗГ if (D12_Read && !f_menu) { menu_dreb = cur_time; f_menu = 1; } if (!D12_Read) { kn_menu = 0; f_menu = 0; } if (f_menu && cur_time - menu_dreb >= 20) { kn_menu = 1; if (!f_Mpush) { menu_klik = cur_time; f_Mpush = 1; } } //Был клик if (f_Mpush && !kn_menu && cur_time - menu_klik < 1000) { if (_UP || _Down) { _UP = 0; _Down = 0; _Mofs1 = 0; _Mofs2 = 0; _Mofs3 = 0; } else Menu++; // Меняем if (Menu > 4) Menu = 1; f_Mpush = 0; } //Было нажатие else if (f_Mpush && !kn_menu && cur_time - menu_klik > 1000) { _Mofs1 = 0; _Mofs2 = 0; _Mofs3 = 0; kalib = !kalib; // Включаем калибровку f_Mpush = 0; } ///////////////////////Проверка кнопки UP - АНТИДРЕБЕЗГ if (D2_Read != f_Up) { //Если сигнал изменился f_Up = !f_Up; Up_dreb = cur_time; } if (kn_Up == D2_Read && cur_time - Up_dreb > 20) kn_Up = !D2_Read; // Было нажатие if (kn_Up && !state_Up) { if (_UP || _Down) { _UP = 0; _Down = 0; _Mofs1 = 0; _Mofs2 = 0; _Mofs3 = 0; state_Up = 1; } else { _UP = !_UP; // Меняем значение state_Up = 1; } } if (!kn_Up)state_Up = 0; // Отпустили ///////////////////////Проверка кнопки DOWN - АНТИДРЕБЕЗГ if (D3_Read != f_Down) { //Если сигнал изменился f_Down = !f_Down; Down_dreb = cur_time; } if (kn_Down == D3_Read && cur_time - Down_dreb > 20) kn_Down = !D3_Read; // Было нажатие if (kn_Down && !state_Down) { if (_UP || _Down) { _UP = 0; _Down = 0; _Mofs1 = 0; _Mofs2 = 0; _Mofs3 = 0; state_Down = 1; } else { _Down = !_Down; // Меняем значение state_Down = 1; } } if (!kn_Down)state_Down = 0; // Отпустили //////////////////////// С кнопками закончили продолжаем логику if (!kalib) { if (Menu != temp_Menu) { temp_Menu = Menu; Serial.print("Menu- "); Serial.println(Menu); switch (Menu) { case 1: D13_High; D14_Low; D7_Low; break; case 2: D13_Low; D14_High; D7_Low; break; case 3: D13_Low; D14_Low; D7_High; break; case 4: D13_High; D14_High; D7_High; break; } } } else { if (cur_time - blink_time >= 300) { blink_time = cur_time; switch (Menu) { case 1: D13_Inv; D14_Low; D7_Low; break; case 2: D13_Low; D14_Inv; D7_Low; break; case 3: D13_Low; D14_Low; D7_Inv; break; case 4: D13_Inv; D14_Inv; D7_Inv; break; } } } /////////////////////////// Запуск 1го двигателя если " perem_X != 0 " if (f_timX) { if (_UP || _Down) { if (!sped_X) { if (Menu == 1 || Menu == 4) { if (!kalib) { //Калибровка отк. if (Shtora1 >= max_Sht1 || Shtora1 <= 0) _Mofs1 = 0; if (Shtora1 < max_Sht1) { if (_Down)_Mofs1 = 1; } if (Shtora1 > 0) { if (_UP) _Mofs1 = 1; } } else { //Калибровка вкл. _Mofs1 = 1; if (_Down) { Shtora1 = 0; } if (_UP) { Shtora1 = 1; } } } if (Menu == 2 || Menu == 4) { if (!kalib) { //Калибровка отк. if (Shtora2 >= max_Sht2 || Shtora2 <= 0) _Mofs2 = 0; if (Shtora2 < max_Sht2) { if (_Down)_Mofs2 = 1; } if (Shtora2 > 0) { if (_UP)_Mofs2 = 1; } } else { //Калибровка вкл. _Mofs2 = 1; if (_Down) { Shtora2 = 0; } if (_UP) { Shtora2 = 1; } } } if (Menu == 3 || Menu == 4) { if (!kalib) { //Калибровка отк. if (Shtora3 >= max_Sht3 || Shtora3 <= 0) _Mofs3 = 0; if (Shtora3 < max_Sht3) { if (_Down)_Mofs3 = 1; } if (Shtora3 > 0) { if (_UP) _Mofs3 = 1; } } else { //Калибровка вкл. _Mofs3 = 1; if (_Down) { Shtora3 = 0; } if (_UP) { Shtora3 = 1; } } } //Три поверки для разгона if (sped_Xt > 0) { --sped_Xt; sped_X = sped_Xt; // f_timX = 0; } } else { --sped_X; f_timX = 0; } }//// else { sped_Xt = uskor; sped_X = 0; } } else { //Для снятия напряжения f_run1X = 1; no_runX = cur_time; } if (_Mofs1)D4_High; else D4_Low; if (_Mofs2)D5_High; else D5_Low; if (_Mofs3)D6_High; else D6_Low; if (f_timX) { if (_Mofs1 || _Mofs2 || _Mofs3) { if (_Down) RunX(0); if (_UP) RunX(1); } } //Возврат по достижению конечной точки if (f_sbrosX) { _UP = 0; _Down = 0; } //Снимаем напряжение с катушек двигателя X if (f_run1X && cur_time - no_runX >= 1000) { f_run1X = 0; PORTB &= 0xF0; f_sbrosX = 1; } }ИМХО надо или класс делать, или структуру. А их них массив - размерностью в количество двигателей.
тогда
switch (Menu) { case 1: if (_Down)Shtora1++; if (_UP)Shtora1--; break; case 2: if (_Down)Shtora2++; if (_UP)Shtora2--; break; case 3: if (_Down)Shtora3++; if (_UP)Shtora3--; break; case 4: if (_Down) { if (_Mofs1)Shtora1++; if (_Mofs2)Shtora2++; if (_Mofs3)Shtora3++; } if (_UP) { if (_Mofs1)Shtora1--; if (_Mofs2)Shtora2--; if (_Mofs3)Shtora3--; } break; }Будет выглядеть как
for( int i = 0; i < MotorCount; i++) { if( motorArr[i].State == HIGH ) { motorArr[i].Shtora += direction; // direction 1 в одну сторону, -1 в другую. } }