- Регистрация
- 23.02.2021
- Сообщения
- 4 866
- Реакции
- 7 727
- Баллы
- 188
- Возраст
- 54
- Адрес
- Россия
- Веб-сайт
- cnc3018.ru
- Город
- Задонск
- Область
- Липецкая
- Имя
- Владимир
- Отчество
- Викторович
- Станок
- CNC 3018 Pro /пока сток/
- Плата
- JLF001 v1.2 /красная/
- Прошивка
- 1,1h
Follow along with the video below to see how to install our site as a web app on your home screen.
Примечание: This feature currently requires accessing the site using the built-in Safari browser.
Потому, что там живёт аппаратный контроллер шины I2CИ почему то рекомендуют именно выводы А4 и А5
дядя Вова, не переживай, с кем не бывает. Кроме того, все знают, что ты у нас больше по ассемблеру.Ну дурак! не посмотрел, поспешил!
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 20, 4);
// 14 пин - контакт A энкодер 1
// 15 пин - контакт C энкодер 1
// 16 пин - контакт A энкодер 2
// 17 пин - контакт C энкодер 2
// контакты В обоих энкодеров - на общий провод
// 4 пин - кнопка энкодера 2
// 5 пин - кнопка энкодера 1
#define DA0_Read (PINC & B00000001) //A0 || 14
#define DA1_Read ((PINC & B00000010)>>1) //A1 || 15
#define DA2_Read ((PINC & B00000100)>>2) //A2 || 16
#define DA3_Read ((PINC & B00001000)>>3) //A3 || 17
#define DA4_Read ((PINC & B00010000)>>4) //A4 || 18
#define DA5_Read ((PINC & B00100000)>>5) //A5 || 19
#define DD4_Read ((PIND & B00010000)>>4)
#define DD5_Read ((PIND & B00100000)>>5)
uint8_t pinA1 = 0; // состояние контакта A
uint8_t pinC1 = 0; // состояние контакта C
bool blockA1 = false; // блокировка прерывания на контакте A
bool blockC1 = false; // блокировка прерывания на контакте C
uint8_t encoder_1 = 0; // Результат энкодера 1
uint8_t pinA2 = 0; // состояние контакта A
uint8_t pinC2 = 0; // состояние контакта C
bool blockA2 = false; // блокировка прерывания на контакте A
bool blockC2 = false; // блокировка прерывания на контакте C
uint8_t encoder_2 = 0; // Результат энкодера 2
volatile uint8_t oldPINC = 0xFF;
bool need_print_1 = true;
bool need_print_2 = true;
int Count_1 = 0;
int Count_2 = 0;
void setup() {
// Прерывание по изменению состояния для A0,A1,A2,A3
PCMSK1 |= (1 << PCINT8) | (1 << PCINT9) | (1 << PCINT10) | (1 << PCINT11);
//разрешить прерывание
PCICR |= (1 << PCIE1);
Serial.begin(115200);
lcd.begin();
lcd.backlight();
lcd.setCursor(0, 0);
lcd.print("Enc 1 = ");
lcd.setCursor(0, 1);
lcd.print("Enc 2 = ");
}
void loop() {
if (need_print_1) {
Serial.print("E1 = ");
Serial.println(Count_1);
need_print_1 = !need_print_1;
}
if (need_print_2) {
Serial.print("E2 = ");
Serial.println(Count_2);
need_print_2 = !need_print_2;
}
if (!DD5_Read) Count_1 = 0;
if (!DD4_Read) Count_2 = 0;
static uint32_t prevMillis = 0;
if (millis() - prevMillis > 250) {
lcdUpdate();
prevMillis = millis();
}
}
void lcdUpdate() {
lcd.setCursor(8, 0);
lcd.print(" ");
lcd.setCursor(8, 0);
lcd.print(Count_1);
lcd.setCursor(8, 1);
lcd.print(" ");
lcd.setCursor(8, 1);
lcd.print(Count_2);
}
// Обработчик запросов прерывания от пинов A0..A3
ISR (PCINT1_vect) {
uint8_t changedbits = PINC ^ oldPINC;
oldPINC = PINC;
if (changedbits & (1 << PC0)) pinA_change_1(); // контакт A энкодер 1
if (changedbits & (1 << PC1)) pinC_change_1(); // контакт C энкодер 1
if (changedbits & (1 << PC2)) pinA_change_2(); // контакт A энкодер 2
if (changedbits & (1 << PC3)) pinC_change_2(); // контакт C энкодер 2
}
// Интерпретируем результат энкодера 2
void get_encoder_1 () {
encoder_1 = encoder_1 & B00001111;
if (encoder_1 == B1011) {
Count_1++; // по часовой
need_print_1 = true;
}
if (encoder_1 == B0111) {
Count_1--; // против часовой
need_print_1 = true;
}
}
// Изменилось состояние контакта А энкодера 1
void pinA_change_1 () {
if (blockA1) return;
pinA1 = !DA0_Read;
pinC1 = !DA1_Read;
encoder_1 <<= 1;
bitWrite(encoder_1, 0, pinA1);
encoder_1 <<= 1;
bitWrite(encoder_1, 0, pinC1);
get_encoder_1();
blockA1 = !(!pinA1 && !pinC1);
blockC1 = false;
}
// Изменилось состояние контакта C энкодера 1
void pinC_change_1 () {
if (blockC1) return;
pinA1 = !DA0_Read;
pinC1 = !DA1_Read;
encoder_1 <<= 1;
bitWrite(encoder_1, 0, pinA1);
encoder_1 <<= 1;
bitWrite(encoder_1, 0, pinC1);
get_encoder_1();
blockC1 = !(!pinA1 && !pinC1);
blockA1 = false;
}
// Интерпретируем результат энкодера 2
void get_encoder_2 () {
encoder_2 = encoder_2 & B00001111;
if (encoder_2 == B1011) {
Count_2 ++;
need_print_2 = true;
}
if (encoder_2 == B0111) {
Count_2 --;
need_print_2 = true;
}
}
// Изменилось состояние контакта А энкодера 2
void pinA_change_2 () {
if (blockA2) return;
pinA2 = !DA2_Read;
pinC2 = !DA3_Read;
encoder_2 <<= 1;
bitWrite(encoder_2, 0, pinA2);
encoder_2 <<= 1;
bitWrite(encoder_2, 0, pinC2);
get_encoder_2();
blockA2 = !(!pinA2 && !pinC2);
blockC2 = false;
}
// Изменилось состояние контакта C энкодера 2
void pinC_change_2 () {
if (blockC2) return;
pinA2 = !DA2_Read;
pinC2 = !DA3_Read;
encoder_2 <<= 1;
bitWrite(encoder_2, 0, pinA2);
encoder_2 <<= 1;
bitWrite(encoder_2, 0, pinC2);
get_encoder_2();
blockC2 = !(!pinA2 && !pinC2);
blockA2 = false;
}
#include <LiquidCrystal_I2C.h>
#include "GyverEncoder.h"
Encoder enc1(14, 15, 5);
Encoder enc2(16, 17, 4);
LiquidCrystal_I2C lcd(0x27, 20, 4);
// 14 пин - контакт A энкодер 1
// 15 пин - контакт C энкодер 1
// 16 пин - контакт A энкодер 2
// 17 пин - контакт C энкодер 2
// контакты В обоих энкодеров - на общий провод
// 4 пин - кнопка энкодера 2
// 5 пин - кнопка энкодера 1
bool need_print_1 = true;
bool need_print_2 = true;
int Count_1 = 0;
int Count_2 = 0;
uint8_t enc1A;
uint8_t enc1B;
uint8_t enc2A;
uint8_t enc2B;
void setup() {
enc1.setType(TYPE2);
enc2.setType(TYPE2);
Serial.begin(115200);
lcd.begin();
lcd.backlight();
lcd.setCursor(0, 0);
lcd.print("Enc 1 = ");
lcd.setCursor(0, 1);
lcd.print("Enc 2 = ");
}
void loop() {
enc1.tick();
enc2.tick();
if (enc1.isLeft()) {
Count_1--;
need_print_1 = true;
}
if (enc1.isRight()) {
Count_1++;
need_print_1 = true;
}
if (enc2.isLeft()) {
Count_2--;
need_print_2 = true;
}
if (enc2.isRight()) {
Count_2++;
need_print_2 = true;
}
if (need_print_1) {
Serial.print("E1 = ");
Serial.println(Count_1);
need_print_1 = !need_print_1;
}
if (need_print_2) {
Serial.print("E2 = ");
Serial.println(Count_2);
need_print_2 = !need_print_2;
}
if (enc1.isPress()) Count_1 = 0;
if (enc2.isPress()) Count_2 = 0;
static uint32_t prevMillis = 0;
if (millis() - prevMillis > 250) {
lcdUpdate();
prevMillis = millis();
}
}
void lcdUpdate() {
lcd.setCursor(8, 0);
lcd.print(" ");
lcd.setCursor(8, 0);
lcd.print(Count_1);
lcd.setCursor(8, 1);
lcd.print(" ");
lcd.setCursor(8, 1);
lcd.print(Count_2);
}
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 20, 4);
// 14 пин - контакт A энкодер 1
// 15 пин - контакт C энкодер 1
// 16 пин - контакт A энкодер 2
// 17 пин - контакт C энкодер 2
// контакты В обоих энкодеров - на общий провод
// 4 пин - кнопка энкодера 2
// 5 пин - кнопка энкодера 1
#define DA0_Read (PINC & B00000001) //A0 || 14
#define DA1_Read ((PINC & B00000010)>>1) //A1 || 15
#define DA2_Read ((PINC & B00000100)>>2) //A2 || 16
#define DA3_Read ((PINC & B00001000)>>3) //A3 || 17
#define DD4_Read ((PIND & B00010000)>>4)
#define DD5_Read ((PIND & B00100000)>>5)
bool need_print_1 = true;
bool need_print_2 = true;
int Count_1 = 0;
int Count_2 = 0;
float m_1 = 0.0f;
float m_2 = 0.0f;
float multiplier = 1.0f;
void setup() {
Serial.begin(115200);
lcd.begin();
lcd.backlight();
lcd.setCursor(0, 0);
lcd.print("Enc 1 = ");
lcd.setCursor(0, 1);
lcd.print("Enc 2 = ");
}
void loop() {
doEncoder_1();
doEncoder_2();
if (need_print_1) {
Serial.print("E1 = ");
Serial.println(Count_1);
need_print_1 = !need_print_1;
}
if (need_print_2) {
Serial.print("E2 = ");
Serial.println(Count_2);
need_print_2 = !need_print_2;
}
static uint32_t prevMillis = 0;
if (millis() - prevMillis > 250) {
lcdUpdate();
prevMillis = millis();
}
}
void doEncoder_1() {
static uint8_t enc_prev_1 = 0;
bool enc_A = DA0_Read;
bool enc_B = DA1_Read;
if ( (!enc_A) && (enc_prev_1) ) {
if (enc_B) {
Count_1 ++;
} else {
Count_1 --;
}
need_print_1 = true;
}
enc_prev_1 = enc_A;
if (!DD5_Read) Count_1 = 0;
}
void doEncoder_2() {
static uint8_t enc_prev_2 = 0;
bool enc_A = DA2_Read;
bool enc_B = DA3_Read;
if ( (!enc_A) && (enc_prev_2) ) {
if (enc_B) {
Count_2++;
} else {
Count_2--;
}
need_print_2 = true;
}
enc_prev_2 = enc_A;
if (!DD4_Read) Count_2 = 0;
}
void lcdUpdate() {
lcd.setCursor(8, 0);
lcd.print(" ");
lcd.setCursor(8, 0);
lcd.print(Count_1);
//m_1 = (float)Count_1 / multiplier;
//lcd.print(m_1, 3);
lcd.setCursor(8, 1);
lcd.print(" ");
lcd.setCursor(8, 1);
lcd.print(Count_2);
//m_2 = (float)Count_2 / multiplier;
//lcd.print(m_2, 3);
}
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 20, 4);
//Подключение энкодеров
// 14 пин - контакт A энкодер 1
// 15 пин - контакт C энкодер 1
// 16 пин - контакт A энкодер 2
// 17 пин - контакт C энкодер 2
// контакты В обоих энкодеров - на общий провод
// 4 пин - кнопка энкодера 2
// 5 пин - кнопка энкодера 1
//замена ардуиновской digitalRead
#define DA0_Read (PINC & B00000001) //A0 || 14
#define DA1_Read ((PINC & B00000010)>>1) //A1 || 15
#define DA2_Read ((PINC & B00000100)>>2) //A2 || 16
#define DA3_Read ((PINC & B00001000)>>3) //A3 || 17
#define DD4_Read ((PIND & B00010000)>>4) //D4
#define DD5_Read ((PIND & B00100000)>>5) //D5
//флаги, разрешающие вывод в сериал-порт
//если вывод не нужен - убираем
bool need_print_1 = true;
bool need_print_2 = true;
//счётчики импульсов энкодеров
int Count_1 = 0;
int Count_2 = 0;
//коэффициент делителя импульсов
const float multiplier = 1.0f;
void setup() {
//инициализируем сериал-порт, если вывод не нужен - убираем
Serial.begin(115200);
//инициализируем дисплей
lcd.begin();
lcd.backlight();
//печатаем неизменяемые поля дисплея
lcdSet();
// Прерывание по изменению состояния A0,A2
PCMSK1 |= (1 << PCINT8) | (1 << PCINT10);
PCICR |= (1 << PCIE1);
}
void loop() {
//опрос кнопок
readButtons();
//вывод в сериал-порт, если вывод не нужен - убираем
print2serial();
//обновление дисплея каждые 250 мсек
static uint32_t prevMillis = 0;
if (millis() - prevMillis > 250) {
lcdUpdate();
prevMillis = millis();
}
}
//обработчик энкодера 1
void doEncoder_1() {
static uint8_t enc_prev_1 = 1;
bool enc_A = DA0_Read;
bool enc_B = DA1_Read;
if ( (!enc_A) && (enc_prev_1) ) {
(enc_B) ? (Count_1++) : (Count_1--);
need_print_1 = true;
}
enc_prev_1 = enc_A;
}
//обработчик энкодера 2
void doEncoder_2() {
static uint8_t enc_prev_2 = 1;
bool enc_A = DA2_Read;
bool enc_B = DA3_Read;
if ( (!enc_A) && (enc_prev_2) ) {
(enc_B) ? (Count_2++) : (Count_2--);
need_print_2 = true;
}
enc_prev_2 = enc_A;
}
//печатаем неизменяемые поля дисплея
void lcdSet() {
lcd.setCursor(0, 0);
lcd.print(F("Enc 1 = "));
lcd.setCursor(0, 1);
lcd.print(F("Enc 2 = "));
}
//вывод значений на дисплей
void lcdUpdate() {
printValue(8, 0, Count_1);
printValue(8, 1, Count_2);
}
//печать значения в указанную колонку-строку
void printValue(uint8_t col, uint8_t row, int value) {
lcd.setCursor(col, row);
lcd.print(F(" "));
lcd.setCursor(col, row);
//выводим целое значение
lcd.print(value);
//или дробное, поделенное на коэффициент
//float fvalue = (float)value / multiplier;
//lcd.print(fvalue, 3);
}
//прерывание порта С
ISR (PCINT1_vect) {
doEncoder_1();
doEncoder_2();
}
//Читаем кнопки обнуления. Нажатием считаем низкий уровень
void readButtons() {
if (!DD5_Read) Count_1 = 0;
if (!DD4_Read) Count_2 = 0;
}
//вывод в сериал-порт, если вывод не нужен - убираем
void print2serial() {
if (need_print_1) {
Serial.print("E1 = ");
Serial.println(Count_1);
need_print_1 = !need_print_1;
}
if (need_print_2) {
Serial.print("E2 = ");
Serial.println(Count_2);
need_print_2 = !need_print_2;
}
}
их тогда нужно будет переключать. Я правильно уловил?на один порт повесить до 8 энкодеров
Переключать не надо. На один порт с общим прерыванием вешаем выводы A энкодеров, на другой порт - выводы С энкодеров. В прерывание порта размещаем обработчики для них.их тогда нужно будет переключать
сразу уточним по терминологии: порт - это группа из 8 пинов (байт), пин - это отдельный вывод контроллера (бит). Портов - три: PB, PD, PC и у каждого есть возможность назначить для отдельных пинов прерывание на изменение уровня. У порта PD имеется возможность назначить двум пинам D2 и D3 "самостоятельные" прерывания INT0 и INT1 с отработкой по лог. 0, 1 или изменению уровня. Тут, конечно не очень удобно, в том плане, что не все пины каждого порта могут использованы, т.к. у PB два пина использованы для подключения кварца, у PD - пара использованы под вход UART, а у PC - под резет и одного, вроде, вообще не выведено.У нас 2 порта прерываний
С дисплеями 1604 или 2004 вполне прокатит до 8 штук. Больше - с прокруткой или переключением экранов.либо под каждый энкодер запрограммировать их позиции на дисплее.
Да. Как аналоговые, они в ардуиновской терминологии А0...А3, а как цифровые - 14...17.Используем входа А0 - А3?
Упаси боже!А что, на самом деле нужно 8 энкодеров подключать?
В моём случае только 2 энкодера.в нашем случае с 3018 это будет излишне!
Тогда вполне достаточно скетча из #113 или сделать аналогично, но на пинах с прерываниями INT0, INT1, как имеющих наивысший приоритет после Reset-а.В моём случае только 2 энкодера.
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 20, 4);
//Подключение энкодеров
// 2 пин - контакт A энкодер 1
// 4 пин - контакт C энкодер 1
// 3 пин - контакт A энкодер 2
// 5 пин - контакт C энкодер 2
// 6 пин - кнопка энкодера 1
// 7 пин - кнопка энкодера 2
// контакты В обоих энкодеров - на общий провод
//замена ардуиновской digitalRead
#define D2_Read ((PIND & B00000100)>>2)
#define D3_Read ((PIND & B00001000)>>3)
#define D4_Read ((PIND & B00010000)>>4)
#define D5_Read ((PIND & B00100000)>>5)
#define D6_Read ((PIND & B01000000)>>6)
#define D7_Read ((PIND & B10000000)>>7)
//флаги, разрешающие вывод в сериал-порт
//если вывод не нужен - убираем
bool need_print_1 = true;
bool need_print_2 = true;
//счётчики импульсов энкодеров
int Count_1 = 0;
int Count_2 = 0;
//коэффициент делителя импульсов
const float multiplier = 10.0f;
void setup() {
//инициализируем сериал-порт, если вывод не нужен - убираем
Serial.begin(115200);
//инициализируем дисплей
lcd.begin();
lcd.backlight();
//печатаем неизменяемые поля дисплея
lcdSet();
// Прерывание по изменению состояния D2,D3
attachInterrupt(0, doEncoder_1,CHANGE);
attachInterrupt(1, doEncoder_2,CHANGE);
}
void loop() {
//опрос кнопок
readButtons();
//вывод в сериал-порт, если вывод не нужен - убираем
print2serial();
//обновление дисплея каждые 250 мсек
static uint32_t prevMillis = 0;
if (millis() - prevMillis > 250) {
lcdUpdate();
prevMillis = millis();
}
}
//обработчик энкодера 1
void doEncoder_1() {
static uint8_t enc_prev_1 = 1;
bool enc_A = D2_Read;
bool enc_B = D4_Read;
if ( (!enc_A) && (enc_prev_1) ) {
(enc_B) ? (Count_1++) : (Count_1--);
need_print_1 = true; //если вывод в сериал не нужен - убираем
}
enc_prev_1 = enc_A;
}
//обработчик энкодера 2
void doEncoder_2() {
static uint8_t enc_prev_2 = 1;
bool enc_A = D3_Read;
bool enc_B = D5_Read;
if ( (!enc_A) && (enc_prev_2) ) {
(enc_B) ? (Count_2++) : (Count_2--);
need_print_2 = true; //если вывод в сериал не нужен - убираем
}
enc_prev_2 = enc_A;
}
//печатаем неизменяемые поля дисплея
void lcdSet() {
lcd.setCursor(0, 0);
lcd.print(F("Enc 1 = "));
lcd.setCursor(0, 1);
lcd.print(F("Enc 2 = "));
}
//вывод значений на дисплей
void lcdUpdate() {
printValue(8, 0, Count_1);
printValue(8, 1, Count_2);
}
//печать значения в указанную колонку-строку
void printValue(uint8_t col, uint8_t row, int value) {
lcd.setCursor(col, row);
lcd.print(F(" "));
lcd.setCursor(col, row);
//выводим целое значение
lcd.print(value);
//или дробное, поделенное на коэффициент
//float fvalue = (float)value / multiplier;
//lcd.print(fvalue, 3);
}
//Читаем кнопки обнуления. Нажатием считаем низкий уровень
void readButtons() {
if (!D6_Read) Count_1 = 0;
if (!D7_Read) Count_2 = 0;
}
//вывод в сериал-порт, если вывод не нужен - убираем
void print2serial() {
if (need_print_1) {
Serial.print("E1 = ");
Serial.println(Count_1);
need_print_1 = !need_print_1;
}
if (need_print_2) {
Serial.print("E2 = ");
Serial.println(Count_2);
need_print_2 = !need_print_2;
}
}
Интернет портал организованный в 2018 году , для поддержки пользователей мини станка с ЧПУ CNC 3018 и его модификаций.
Мы хотели бы помочь всем, кто приобрел или только собирается приобрести данный станок. Здесь Вы совершенно спокойно можете задать свои вопросы, или просто прочитать полезную или интересную информацию по сборке, настройке и эксплуатации данного мини станка.
МЫ ДОГАДЫВАЕМСЯ, ЧТО РЕКЛАМА ВАС РАЗДРАЖАЕТ!
Конечно, Ваше программное обеспечение для блокировки рекламы отлично справляется с блокировкой рекламы на нашем сайте, но оно также блокирует полезные функции. Мы стараемся для Вас и не обязываем Вас донатить и скидывать денег на наши кошельки, чтобы пользоваться форумом, но реклама это единственное, что позволяет поддерживать проект и развивать его.
Спасибо за Ваше понимание!