#include "stm8l10x.h"
#define LED_PORT GPIOC
#define LED_PIN GPIO_Pin_2 // вывод 20
#define LED_TOGGLE() (GPIO_ToggleBits(LED_PORT, LED_PIN))
//#define LED_ON() (GPIO_WriteBit(LED_PORT, LED_PIN, SET)) - это говно не работает!!!
//#define LED_OFF() (GPIO_WriteBit(LED_PORT, LED_PIN, RESET)) - - это говно не работает!!!
#define LED_ON() (LED_PORT->ODR |= GPIO_Pin_2)
#define LED_OFF() (LED_PORT->ODR &= ~GPIO_Pin_2)
#define BTN_GPIO_PORT GPIOB
#define BTN_GPIO_PIN GPIO_Pin_7 // порт PB7 (17) - вход кнопки
#define BTN_PRESSED() (!GPIO_ReadInputDataBit(BTN_GPIO_PORT, BTN_GPIO_PIN))
#define TIM2_PERIOD 1000 // период таймера 2
/* константы для режима свечи, все времена в миллисекундах */
#define MIN_DELAY_BEFORE_DOWN 1
#define MAX_DELAY_BEFORE_DOWN 1000
#define MIN_PERIOD_DOWN 200 // минимальная длительность угасания
#define MAX_PERIOD_DOWN 300 // максимальная длительность угасания
#define MIN_BRIGHTNESS_DOWN 100 // минимальное значение яркости, до которого будет угасать свеча (значение подбирается экспериментально)
#define MAX_BRIGHTNESS_DOWN 900 // максимальное значение яркости, до которого будет угасать свеча (значение подбирается экспериментально)
#define MIN_PERIOD_UP 200 // минимальная длительность разгорания
#define MAX_PERIOD_UP 500 // максимальная длительность разгорания
#define TIMER_INTERVAL 25 // периодичность срабатывания прерывания
#define MAX_BRIGHTNESS 900 // максимально возможное значение яркости (подбирается экспериментально во току светодиода 20мА)
#define set_brightness(br) TIM2_SetCompare2(br)
#define WORK_TIME_VALUE (720000UL) // время непрерывной работы в тиках 40 Гц таймера = 5ч * 60 м * 60 с * 40 Гц
//#define WORK_TIME_VALUE (24000UL) // ***debug***
////////////// прототипы ///////////////
static void TIM2_Config(void);
static void TIM4_Config(void);
void Delay(__IO uint16_t nCount);
uint16_t candleMode(void);
void EnterLowPowerMode();
void ExitLowPowerMode();
// uint16_t lighthouseMode(void);
/* немного рандомной магии */
#define RAND_MAX 32767
uint16_t rand(void);
uint16_t random(uint16_t minval, uint16_t maxval);
// функция возвращает псевдослучайное число из диапазона [0; RAND_MAX]
uint16_t rand()
{
static uint32_t next=1;
next=next*1103515245+12345;
return((uint16_t)(next/65536)%32768);
}
// функция возвращает псевдослучайное число из диапазона [minval; maxval]
uint16_t random(uint16_t minval, uint16_t maxval)
{
return ((uint16_t)(((maxval-minval)*1UL*rand())/RAND_MAX) + minval);
}
enum mode_T {OFF, ON, TRY_OFF} work_mode, next_mode;
volatile uint16_t g_pwm_value = 0;
volatile uint32_t g_off_counter = WORK_TIME_VALUE; // время, оставшееся до выключения
/* Что делать с неииспользуемыми выводами:
By default, the I/Os are configured as floating input.
It is important to change the configuration of all I/Os that are not connected to defined logic
signals so as to obtain one of the following configurations:
- input configuration with pull-up
- or, output configuration with a low (or high) logic level
Otherwise, an increased consumption is generated by noise, as the internal Schmitt triggers
detecting this noise are toggling.
Floating I/Os could generate additional consumption in the range of a few 10 µA.
There are also parts with some unbonded I/Os (typically different packages of the same
product). Those I/Os are connected to a defined level by factory option configuration, unless
otherwise specified in the datasheet.
*/
void main(void)
{
CLK_MasterPrescalerConfig(CLK_MasterPrescaler_HSIDiv8); // максимальный делитель = минимальная частота 16/8 = 2 МГц
TIM2_Config();
TIM4_Config();
//GPIO_Init(LED_PORT, LED_PIN, GPIO_Mode_Out_PP_Low_Fast); // вывод для светодиода для отладки
GPIO_Init(BTN_GPIO_PORT, BTN_GPIO_PIN, GPIO_Mode_In_PU_IT); // вход с подтяжкой с внешним прерыванием
EXTI_SetPinSensitivity(EXTI_Pin_7, EXTI_Trigger_Falling);
// неиспользуемые порты на выход и в 0
GPIO_Init(GPIOA, GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3, GPIO_Mode_Out_PP_Low_Slow); // выводы 3, 4, 5, 6
GPIO_Init(GPIOB, GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_5|GPIO_Pin_6, GPIO_Mode_Out_PP_Low_Slow); // выводы 10, 11, 12, 13, 15, 16
GPIO_Init(GPIOC, GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4, GPIO_Mode_Out_PP_Low_Slow); // выводы 18, 19, 20, 1, 2
GPIO_Init(GPIOD, GPIO_Pin_0, GPIO_Mode_Out_PP_Low_Slow); // выводы 9
work_mode = OFF;
set_brightness(0);
/* Enable interrupts*/
enableInterrupts();
while (1)
{
;
}
}
static void TIM2_Config(void)
{
/* Enable TIM2 clock */
CLK_PeripheralClockConfig(CLK_Peripheral_TIM2, ENABLE);
/* Config TIM2 channel 2 pins */
GPIO_Init(GPIOB, GPIO_Pin_2, GPIO_Mode_Out_PP_High_Fast); // вывод PB2 (12)
/* Time base configuration */
// 2 МГц/1000 = 2000 Гц
TIM2_TimeBaseInit(TIM2_Prescaler_1, TIM2_CounterMode_Up, TIM2_PERIOD);
/* PWM1 Mode configuration: Channel2 */
TIM2_OC2Init(TIM2_OCMode_PWM1, TIM2_OutputState_Enable, 0, TIM2_OCPolarity_High, TIM2_OCIdleState_Set); // вывод PB2/TIM2_CH2/(12)
TIM2_OC2PreloadConfig(ENABLE);
TIM2_ARRPreloadConfig(ENABLE);
TIM2_SetCompare2(0);
/* Enable TIM2 outputs */
TIM2_CtrlPWMOutputs(ENABLE);
/* TIM2 enable counter */
TIM2_Cmd(ENABLE);
}
static void TIM4_Config(void)
{
/* Enable TIM4 CLK */
CLK_PeripheralClockConfig(CLK_Peripheral_TIM4, ENABLE);
TIM4_DeInit();
/* Time base configuration */
TIM4_TimeBaseInit(TIM4_Prescaler_256, 195); // 2 МГц / 256 / 195 = 40 Гц
TIM4_ITConfig(TIM4_IT_Update, ENABLE);
TIM4_ARRPreloadConfig (ENABLE);
/* Enable TIM4 */
TIM4_Cmd(ENABLE);
}
// функция мерцания свечи
uint16_t candleMode(void)
{
/* переменные */
static uint8_t step = 0; // 0 - delay, 1 - down, 2 - up
static uint16_t needBrightness = MAX_BRIGHTNESS; // требуемое значение яркости
static uint16_t curBrightness = MAX_BRIGHTNESS; // текущее значение яркости
static uint16_t oneStep = 0; // шаг изменения яркости
static uint16_t curPeriod = 0; // длительность изменения свечения
static uint16_t delayBeforeDownUp = 0;
if(step == 0) // долгая задержка перед очередным угасанием
{
if (delayBeforeDownUp == 0) // генерация значений для следующего шага
{
step = 1;
needBrightness = random(MIN_BRIGHTNESS_DOWN, MAX_BRIGHTNESS_DOWN);
curPeriod = random(MIN_PERIOD_DOWN, MAX_PERIOD_DOWN);
oneStep = ((MAX_BRIGHTNESS - needBrightness) * TIMER_INTERVAL) / curPeriod; // шаг времени для каждого вызова функции
if (oneStep == 0) oneStep = 1; // если шаг получился нулевой, делаем его минимальным
}
else
{
if (delayBeforeDownUp > TIMER_INTERVAL) delayBeforeDownUp -= TIMER_INTERVAL;
else delayBeforeDownUp = 0;
}
}
else if(step == 1) // down
{
if (curBrightness == needBrightness) // генерация значений для следующего шага
{
step = 2;
needBrightness = MAX_BRIGHTNESS;
curPeriod = random(MIN_PERIOD_UP, MAX_PERIOD_UP);
oneStep = ((MAX_BRIGHTNESS - curBrightness) * TIMER_INTERVAL) / curPeriod;
if (oneStep == 0) oneStep = 1;
}
else
{
if ((curBrightness - needBrightness) > oneStep) curBrightness -= oneStep;
else curBrightness = needBrightness;
}
}
else
{
if (curBrightness == needBrightness) // генерация значений для следующего шага
{
step = 0;
delayBeforeDownUp = random(MIN_DELAY_BEFORE_DOWN, MAX_DELAY_BEFORE_DOWN);
}
else
{
if ((needBrightness - curBrightness) > oneStep) curBrightness += oneStep;
else curBrightness = needBrightness;
}
}
return curBrightness;
}
// бонусная функция имитации мерцания маяка (плавное нарастание -> плавный спад)
uint16_t lighthouseMode(void)
{
static uint8_t direction = 1; // верх
const uint16_t max_pwm = 900;
static uint16_t cur_pwm = 0;
static uint16_t pwm_step = 40; // шаг прибавления/убавления яркости
if(direction == 1)
{
if(cur_pwm + pwm_step < max_pwm) cur_pwm += pwm_step;
else
{
cur_pwm = max_pwm; direction = 0;
}
}
else // direction == 0
{
if(cur_pwm > pwm_step) cur_pwm -= pwm_step;
else
{
cur_pwm = 0; direction = 1;
}
}
return cur_pwm;
}
volatile uint16_t shake_counter = 0; // счетчик потрясываний
volatile bool halt_flag = FALSE; // флаг перехода в режим сна
// прерывание по совпадению таймера 4 (частота срабатывания 40 Гц)
INTERRUPT_HANDLER(TIM4_UPD_OVF_IRQHandler, 25)
{
const uint16_t pwm_step = MAX_BRIGHTNESS / 2 / 40; //
static uint16_t delay_counter = 0;
static const uint16_t delay_time = 16; // 400 мс
static const uint16_t delay_before_halt = 10 * 40; // время, которое МК пробудет в выключенном состоянии, перед тем как заснуть (в тиках таймера)
static uint16_t halt_counter = 10 * 40;
static uint32_t work_counter = WORK_TIME_VALUE;
switch(work_mode)
{
case OFF:
{
if(delay_counter > 0) // задержка включена для того, что бы после выключения светильник не начал опять включаться
{
if(shake_counter > 0)
{
shake_counter = 0;
}
else
{
delay_counter--;
}
}
else
{
if(shake_counter > 0) // если состояние изменилось
{
shake_counter = 0;
if(g_pwm_value < MAX_BRIGHTNESS - (pwm_step))
g_pwm_value += (pwm_step);
else
{
work_mode = ON;
//g_off_counter = g_off_value;
delay_counter = delay_time;
}
}
else
{
if(g_pwm_value > (pwm_step))
g_pwm_value -= (pwm_step);
else
g_pwm_value = 0;
}
if(g_pwm_value == 0) // если текущая яркость нулевая, пробуем заснуть, если никто не начнет опять трясти
{
if(halt_counter > 0)
{
halt_counter--;
}
else // дождались
{
halt_counter = delay_before_halt;
halt_flag = TRUE;
TIM4_ClearITPendingBit(TIM4_IT_Update); // сброс флага прерывания, что бы МК смог уснуть
__halt();
}
}
}
set_brightness(g_pwm_value);
}
break;
case ON:
{
set_brightness(candleMode());
if(delay_counter > 0) // если требуется задержка
{
if(shake_counter > 0)
{
shake_counter = 0;
}
else
{
delay_counter--; // счетчик уменьшаем только тогда, когда кнопка отпущена
}
}
else // отработка тряски
{
if(shake_counter > 0) // светильник трясут
{
shake_counter = 0;
g_pwm_value = MAX_BRIGHTNESS;
work_mode = TRY_OFF;
}
}
if(work_counter > 0)
{
work_counter--;
}
else
{
// кончилось время работы
g_pwm_value = 0;
set_brightness(g_pwm_value);
work_counter = WORK_TIME_VALUE;
work_mode = OFF;
}
} //end of case ON:
break;
case TRY_OFF:
{
if(shake_counter > 0) // есть тряска
{
shake_counter = 0;
if(g_pwm_value > pwm_step)
g_pwm_value -= pwm_step; // пока можно, уменьшаем яркость до 0
else // если дошли до 0
{
g_pwm_value = 0;
delay_counter = delay_time;
work_mode = OFF; // режим выключения
}
}
else // прекратили трясти
{
if(g_pwm_value < MAX_BRIGHTNESS - pwm_step)
g_pwm_value += pwm_step; // постепенно наращиваем яркость до максимума
else // дошли до максимума
{
work_mode = ON;
}
}
set_brightness(g_pwm_value);
} // end case TRY_OFF
break;
}
TIM4_ClearITPendingBit(TIM4_IT_Update);
}
// прерывание по входу на пине PB7 (17)
INTERRUPT_HANDLER(EXTI7_IRQHandler, 15)
{
//LED_TOGGLE(); // **** debug ****
if(shake_counter < U16_MAX) shake_counter++;
if(halt_flag) // если МК вышед из сна
{
halt_flag = FALSE;
}
EXTI_ClearITPendingBit(EXTI_IT_Pin7);
}
void Delay(__IO uint16_t nCount)
{
/* Decrement nCount value */
while (nCount != 0)
{
nCount--;
}
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval : None
*/
void assert_failed(uint8_t* file, uint32_t line)
{
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* Infinite loop */
while (1)
{
}
}
#endif
Другое дело что stm32f030 стоит 0.5$ и по всем параметрам кладет на лопатки stm8l, кроме потребления. Но у stm32 тоже же есть l серия. Не стоит забывать что числа больше 255 уже 16 и 32бита. Условно говоря для 32бит МК это одна инструкция, а у 8мибитника это простыня из 8мибитных команд.
Про stm8s даже говорить не о чем. Сейчас за 0.25$ можно купить n76e003. За эти деньги 18Кб памяти, 12бит АЦП, 3x2 канала ШИМ.
stm8 вообще никуда не вписывается при таких раскладах.
P.S. Я SPL не перевариваю, предпочитаю регистры, поэтому мельком пробежался по программе. Вроде ничего. Но не хватает хотя бы перехода в WFI в основном цикле, чтобы процессор зря не молотил и не расходовал батарейку.
Но пока так и не нашлось задачи, где бы stm8l151 понадобился, лежат в коробке :).
www.youtube.com/watch?v=7nVMRmfJnZg
Суть что луч 2 зеркала двигают.
Делиться он не стал проектом. galvo scanner продаются на али за 60$. но этот парень писал что с али плохие. Можно было бы попробовать. Но это сколько свободного времени нужно чтобы разобраться разработать контроллер и софт и довести до ума :).
Там кстати на али и установки мощные продаются и голову я отдельно находил, можно металл сразу выжигать. Типа такого
www.youtube.com/watch?v=mzmjGz0_joM
Можно наверное и бизнес открыть по гравировке на металле, может еще и окупится ))
www.youtube.com/watch?v=fDLgsEnmYu0
Частью струйника сейчас светят фоторезист на текстолите, сделав подвижный стол.
www.youtube.com/watch?v=kDNkFRPtxv0
У Nuvotona аж 2 варианта в qfn 3x3. Но на али совместимый с stm8. aliexpress.com/item/10PCS-N76E003AQ20-N76E003-AQ20-QFN-20/32951884618.html Но цена уже не 0.25$ как за tssop, не так популярны.
Новотон дешевле stm8s, но памяти 18К и 12бит АЦП и пашут от 2.4В, а у stm8s 8K и 10бит. За 0.5$ уже stm32f030 покупается.
Я к нувотону сразу привык, шпарю прямо на ассемблере :).
а у них есть аналог stm8l
П.С, Думаю за программатор для нувотонов из st link вам бы многие сказали спасибо))
Но они разные с stm8s, у каждого свои плюсы и минусы. Плюсы я написал выше. И еще выше писал про 3x2 шим. Целые порты по 8 бит шириной P0.0-P0.7, P1.0-P1.7, а не как у стмки обрубки портов. Я могу сказать и минусы нувотона. Нувотон с кварцем не работает, если нужна кварцевая точность — отпадает. От внутренней цепочки обещают <2%. У новотона 3 такта на смену состояния ноги, против 1 такта у stm, если это критично (я говорю о ногодрыге, а не о железных интерфейсах, интерфейсы как у всех собратьев, тот же spi 8МГц).
У stm32 всего 3 компилятора все те же ARM (Keil), IAR и бесплатный GCC. Хотя на последнем могут быть и платные IDE.
Однако в документации на SK9822 PWM 1.2 кГц. На apa102 не нашёл в документации частоту, но вряд ли там 20 кГц
4.2кГц у SK9822 у человека на видео. И 20кГц APA102.
У меня SK9822 лежат, не дошли руки до них пока.
Не понятно почему они в документах написали 1.2 кГц…
и светодиодик лучше RGB поставить… чтоб цвет кубик менял…
И благодарность тем, кто предлагает прочие вариации по теме.
Вот-вот..-это уровень IQ подобных «оппонентов», и, не более…
И да я понимаю, что мы живем в реальном мире, в котором у проводов есть паразитная индуктивность и емкость. Ключ открывается не мгновенно и не до конца и т. д. И за счет паразитных индуктивностей, емкостей шимируя светодиод на высокой частоте можно корректно ограничивать ток через него. Но мне кажется это как то несерьезно полагаться только на непредсказуемые паразитные процессы.
Для влияния паразитных емкостей и индуктивностей тут слишком маленькая частота — 2 КГц.
PS: Закидали помидорами :( В следующий раз обязательно поставлю резистор на символические ом 10.
Т.е. миримальное по размеру устройство с bluetooth, которое эпизодически по BLE подключается к смартфону. В програмке на смартфоне выбирается режим мерцания или цвет светодиода
или nRF52832, на али есть модуль размером вообще 10*10мм.
Есть вот такая фоточка
www.st.com/en/microcontrollers/stm32l0-series.html?querycriteria=productId=SS1817
так, на всякий случай, слева nRF52832, справа СС2540 в виде модуля JDY-08.
Как раз заказал на днях на пробу платку за 3.5$. Будет у меня с удаленных датчиков инфу передавать. :).
nRF52832 же кортекс и по идее есть выбор использования бесплатного ARM GCC.
СС проигрывает и по потреблению, судя по таблицам.
У TI, кстати, тоже есть серия на кортексе.
1.за что платят больше.
2.что знаешь лучше.
И толку что тебе кто-то подскажет какую-то Busy Bee если ты ее не знаешь, никто тебе не заплатит за ее изучение и никто не купит твои знания в будущем?
А как именно IDE, как раз — полное днище.
Ну и гцц для нрф есть вообще-то…
Ты запускаешь IDE, открываешь своё workspace. IDE шлет на сервер твою сигнатуру и опции твоего workspace. Обратно сервер шлет тебе модуль конкретно под это workspace, в котором будут компиляторы, линкеры, библиотеки. Модуль зашифрован, привязан ко времени и к твоей сигнатуре.
Следующие 24 часа ты работаешь оффлайн ровно так-же как работаешь прямо сейчас. Через 24 часа подгруженный модуль перестает работать и надо опять подключаться к серверу, слать в него сигнатуру и получать новый модуль.
Твоя сигнатура это грубо говоря твой счет, закинул на него денежку- получаешь свежие модули и работаешь, не закинул- не получаешь.
Пытаться ломать бесполезно, вся крипта интегрирована в винду десятку, и с каждым обновлением становится все злее и злее.
— Во-первых, не обязательно все собирать самому-можно нанять специалиста. А чтобы нанять — полезно послушать мнение опытных людей.
— Во вторых, интересно иногда и изучить.
— В третьих, я с уважением отношусь к людям, которые лучшим продуктом считают свои умения, но, к сожалению, я к ним не отношусь.
Не нужно лезть в процесс выбора элементарной базы если не обладаешь необходимыми для этого знаниями, ничего хорошего от опытных специалистов ты не услышишь потому что каждый свое болото хвалит и холивары на тему и51-мсп-пик-авр-тмс-стм-лпц-сам однажды начавшись не закончатся никогда.
Во первых у вас по определению не совпадают цели (у работника — дорого и с минимальными результатами; у вас — цена, качество, стоимость поддержки, зависимость от определенного типа работников).
В во вторых (и главных) — если вы не вникаете в детали, проблемы, процесс — то на выходе получаете инструмент, который не вам нужен, а вашему нанятому специалисту.
к сожалению, в жизни шары нет, и нужно вникать в процесс.
Когда же мы говорим о процессе значительно более сложном, чем изготовление деревянной двери, для «вникнуть в процесс» надо обладать глубокими знаниями и серьезным опытом работы как минимум с несколькими из платформ, и, самое главное, иметь опыт разработки подобного устройства работающего в подобных условиях.
Если всего этого лично у тебя нет то твое «вникнуть в процесс» будет пересказом мнения самого красноречивого из своих интернет консультантов, компетентность которого у тебя нет возможности проверить, а попытка затянуть его в дискуссию с другими консультантами моментально превратится в холивар, в котором ты ничего не поймешь, потому что абсолютно все участники этого холивара ПРАВЫ.
Эти типичный случай, когда каждый суслик в поле агроном.
aliexpress.com/item/CDEBYTE-E73-2G4M08S1C-nRF52840-BLE-5-0-Wireless-Transceiver-8dbm-120m-2-4GHz-Ceramic-Antenna-2/32944356249.html
Есть вот такая интересная плата, но цена не радует: aliexpress.com/item/New-product-NRF52832-Bluetooth-wireless-sensor-acceleration-sensor-BME280-environment-sensor/32812724646.html
Для примера:
Garmin Vivosmart – nRF51422 by Nordic Semiconductor
Misfit Flash Link – nRF51822 by Nordic Semiconductor
Pebble Time – CC2564 by Texas Instruments
FitBit Surge – CC2564 by Texas Instruments
Misfit Shine Activity Tracker – CC2541 by Texas Instruments
Xiaomi Mi Band – DA14580 by Dialog Semiconductor
FitBit Charge 2 – BLUENRGCSP by STMicroelectronics
Samsung Gear Fit – BCM4334WKUBG by Broadcom
Нужно смотреть не просто кто на чем сделал, а платная или бесплатная будет среда разработки, комьюнити для помощи и т.д.
И если посмотреть, то DA14580 потребляет меньше из-за использования OTP памяти.
Ты серьезно?