Переделка китайского шейкера
Достался простейший взбиватель сливок (жидкости) из поднебесной без регулировки скорости. Нажал - вертит, отпустил - остановился.
Бывает необходимо в маленьких колличествах размешать краски. Делать это лучше не на реактивных оборотах мотора. А еще довольно желательно не держать нажатой кнопку постоянно пока пользуешся. Некий "latch" состояния последнего.
Ввиду этого разобрал устройство что-бы узнать что можно предпринять малыми усилиями. Внутри обычный безымянный двигатель зацепленый за импровизированную кнопку которая перемыкает контакты электрической цепи из двух пальчиковых батареек зацепленых на мотор).
Можно сделать на КМОП таймере 555 ШИМ но поскольку желательно сохранить штатную кнопку и надо иметь хотя-б 3 скорости то
потребуется хоть и маленький но микроконтроллер. в роли него выступит ATTINY10.
Функционал простой: держим несколько секунд - включается на максимальные обороты , далее длинными нажатиями обороты, ступенчато, 4 раза снижаются. после чего последнее длинное нажатие выключает мотор и погружает МК в сон. Решение о том что после включения крутится он начинает с максимальных оборотов не спроста - вначале двигатель управляемый ШИМом надо "сдернуть" для чего и используется полная подача питания через полевой транзистор.
Первый прототип печатной платы с началом подгона под стесненные размеры корпуса.
Конденсаторы всегда имеют утечки. В данном устройстве конденсатор нужен для балансировки питания МК в моменты старта мотора. Минимальный практический обьем емкости 4.7мкф. Меньше емкости этой - нестабильность питания приводит к переколбасу МК, больше - излишние утечки и поедания впустую батарейного питания.
Для подводки питания в стесненном корпусе выбрал толстые многожильные провода. Диод защиты напаян на сами клеммы мотора.
Кстати, в моем экземпляре, мотор довольно сильный дисбаланс имеет и значительно вибрирует. От клемм питания к плате идет жесткий моножильный кусок обмоточного провода который обеспечивает еще и удержание платы в задуманном положении. Тактовая микро-кнопка закреплена на пару капель спермоклея (tm) из поднебесной. Оригинальная пластиковая кнопка с толкателем были чуточку подпилены что-бы штырь-толкатель не продавливал очень сильно тактовую кнопку.
в целом устройство собиралось за несколько вечеров.
Исходный код прошивки написан в Atmel Studio и довольно прост.
/*
* firmware for primitive chinese hand 3V DC motor shaker. support OFF/MAX/MEDIUM/LOW/VERY LOW speed setting via single button
*
* Author : dukk
*/
#define F_CPU 2000000
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
uint8_t mode=5;
//Variable to tell main that the button is pressed (and debounced). Main will clear it after a detected button press
volatile uint8_t button_down = 1;
void powerdown()
{
//disconnect timer from OUTPUT on pin
TCCR0A &= ~(1<<COM0B1);
PORTB &= ~ (1<<PORTB1);
while(1)
{
cli();
button_down=0;
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_enable();
sei();
sleep_cpu();
sleep_disable();
TCCR0B |= (1 << CS01);
//wait 32 timer overflows so our overflow interrupt can do debounce stuff
for(uint8_t i=0;i<32;i++) {
while ((TIFR0 & (1 << TOV0)) == 0);
}
//check button state after -> if it is surely detected as pressed - get out of sleep
if(button_down) break;
}
//connect timer to OUTPUT pin
TCCR0A |= (1<<COM0B1);
}
EMPTY_INTERRUPT(INT0_vect)
// Check button state on PB2 and set the button_down variable if a debounced button down press is detected.
ISR(TIM0_OVF_vect)
{
// Counter for number of equal states
static uint8_t count = 0;
// Keeps track of current (debounced) state
static uint8_t button_state = 0;
// Check if button is high or low for the moment
uint8_t current_state = (~PINB & (1<<PINB2)) != 0;
if (current_state != button_state) {
// Button is about to be pressed or released, increase counter
count++;
//at every 24ms *32 = 738ms debounce time
if (count >= 32) {
// The button have not bounced, change state
button_state = current_state;
// If the button was pressed (not released), tell main so
if (current_state != 0) {
button_down = 1;
count = 0;
}
}
} else {
// Reset counter
count = 0;
}
}
int main(void)
{
cli();
// Set clock to 2 MHz
CCP = 0xD8;
CLKPSR = 2; //Fosc/4
WDTCSR |= (0<<WDE);
PRR = (1<<PRADC);
ACSR = (1<<ACD);
//out PWM to PB1, all other is input
DDRB = (1<<DDB1); //PB1
//enable pull-up internal on PB2 (power and speed control button)
PUEB = (1<<PUEB2);
PORTB |= (1<<PUEB2);
//Configure interrupt
EICRA = (1<<ISC00); //any logic change INT0 generate interrupt
SREG |= 1<<7;//I bit from SREG has to be enabled
EIMSK |= (1 << INT0);//enable INT0 (PB2)
//Timer0 in mode 14, fast PWM with ICR0 as top, Enable OC0B, low mode bits
TCCR0A = (1<<COM0B1) | (1<<WGM01);
//top value for counter
ICR0 = 3072;
// Enable overflow interrupt (at div8 it will overflow every 24ms)
TIMSK0 = 1<<TOIE0;
// Start timer with prescaler 1:8, high mode bits
TCCR0B = (1<<CS01) | (1<<WGM03) | (1<<WGM02);
sei();
while(1)
{
if (button_down) {
// Clear flag
button_down = 0;
if(++mode > 4) mode=0;
switch(mode) {
case 0:
powerdown();
break;
case 1:
OCR0B = 3072;
break;
case 2:
OCR0B = 2048;
break;
case 3:
OCR0B = 1024;
break;
case 4:
OCR0B = 512;
break;
}
}
}
}
There are no published comments.
New comment