после истории с чеком, ты думаешь у меня есть хоть толика стимула, иметь дело с тобой? ![]()
и еще раз, объясни всем, при чем тут STM и какая то PUYA, коих ты наковырял ведро из картриджей в своем сервис центре?
после истории с чеком, ты думаешь у меня есть хоть толика стимула, иметь дело с тобой? ![]()
и еще раз, объясни всем, при чем тут STM и какая то PUYA, коих ты наковырял ведро из картриджей в своем сервис центре?
“за каждым павлиньим хвостом скрывается обычная куриная жопа” ARM Cortex M0+
Недавно потребовался диммер. Написал на CH32V003 восьминожке с управлением по СОМ порту от 0 до полного напряжения питания. Подобный китайцы продают вот здесь https://aliexpress.ru/item/1005011583805008.html?sku_id=12000056226465848 Задач дофига что на этом контроллере можно делать. И что, действительно нельзя считать его флеш, для дальнейшего использования в своих целях?
если включили RDP2 то в мусорку, если RDP1 можно просто сбросить и шей свою программу
Так я правильно понял считать всё же флеш с CH32V003 нельзя. Просто сбрасывать нет смысла т.к. стоит она 10 рублей на озоне. Или всё же за очень большие деньги можно))))
это не АРМ, дел не имел, тут мой ответ про RPD - возможно вообще этот гвоздь не в тут стену, посмотрел, есть RDP1
тебе подпись на форуме надо дополнить этой фразой)
обычно просят от крутёлки, да ещё три канала, чтобы по трём фазам управлять, ацп там есть, три платки каждая на свою фазу, писал ПО на Attiny85, но у них сейчас цена недемократичная
я не жадный, один канал, по I2C, сериал для отладки, на восьминожке выкинешь!
/*
* AC Dimmer for CH32V003 (Phase Control)
* Детектор нуля на PD2 (внешнее прерывание),
* управление симистором на PD4.
* Задержка 0..10000 мкс (полупериод 50 Гц).
* Управление через I2C (адрес 0x30) или Serial.
*/
#include <Wire.h>
#define ZC_PIN PD2 // вход детектора нуля
#define TRIAC_PIN PD4 // управление симистором
#define I2C_ADDR 0x30
volatile uint16_t delayMicro = 0; // задержка 0..10000 мкс
volatile uint8_t pwmValue = 0; // 0..255
// Обработчик прерывания по переходу через ноль
void zeroCrossISR() {
// Запускаем таймер с задержкой delayMicro
TIM2->CNT = 0;
TIM2->ATRLR = delayMicro; // период задержки
TIM2->CTLR1 |= 0x0001; // бит CEN = 1 (запуск)
}
// Обработчик прерывания от таймера TIM2 (по переполнению)
void TIM2_IRQHandler() {
if (TIM2->INTFR & 0x0001) { // бит UIF (флаг обновления)
TIM2->INTFR = 0x0001; // сброс флага записью 1
// Подаём импульс на симистор
digitalWrite(TRIAC_PIN, HIGH);
delayMicroseconds(50); // длительность импульса ~50 мкс
digitalWrite(TRIAC_PIN, LOW);
TIM2->CTLR1 &= ~0x0001; // бит CEN = 0 (остановка)
}
}
// Обработчик I2C приёма
void receiveEvent(int howMany) {
if (howMany > 0) {
uint8_t reg = Wire.read();
if (reg == 0x00 && howMany > 1) {
pwmValue = Wire.read();
delayMicro = map(pwmValue, 0, 255, 0, 10000);
}
}
}
// Обработчик I2C запроса
void requestEvent() {
Wire.write(pwmValue);
}
void setup() {
// Отладка через Serial (опционально)
Serial.begin(115200);
Serial.println("AC Dimmer CH32V003 ready");
// Настройка пинов
pinMode(TRIAC_PIN, OUTPUT);
digitalWrite(TRIAC_PIN, LOW);
pinMode(ZC_PIN, INPUT_PULLUP);
// --- Настройка TIM2 ---
// Включаем тактирование TIM2
RCC->APB1PCENR |= RCC_APB1Periph_TIM2; // 0x00000001
TIM2->CTLR1 = 0x0084; // ARPE=1 (бит7), URS=1 (бит2), CEN=0
TIM2->PSC = 47; // 48 МГц / 48 = 1 МГц (1 тик = 1 мкс)
TIM2->ATRLR = 10000; // макс. задержка 10 мс
TIM2->CNT = 0;
TIM2->DMAINTENR = 0x0001; // разрешить прерывание по обновлению (UIE)
// Разрешаем прерывание от TIM2
NVIC_EnableIRQ(TIM2_IRQn);
NVIC_SetPriority(TIM2_IRQn, 1);
// --- Внешнее прерывание на PD2 (детектор нуля) ---
// attachInterrupt(пин, режим_пина, колбэк, режим_EXTI, триггер)
attachInterrupt(
digitalPinToInterrupt(ZC_PIN),
GPIO_Mode_IN_FLOATING,
zeroCrossISR,
EXTI_Mode_Interrupt,
EXTI_Trigger_Rising_Falling // или EXTI_Trigger_Rising/Falling
);
// --- I2C Slave ---
Wire.begin(I2C_ADDR);
Wire.onReceive(receiveEvent);
Wire.onRequest(requestEvent);
// Индикация работы (встроенный светодиод)
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, HIGH);
}
void loop() {
// Управление через Serial (для отладки)
if (Serial.available()) {
int val = Serial.parseInt();
if (val >= 0 && val <= 255) {
pwmValue = val;
delayMicro = map(pwmValue, 0, 255, 0, 10000);
Serial.print("Brightness: ");
Serial.println(pwmValue);
} else {
Serial.println("Enter 0..255");
}
}
delay(100);
}
Даже на последней 1.0.4 не работает из коробки для этого мк в Arduino IDE . Надо библиотеки хардовые менять.
выкинь весь сериал, осциллограф наше всё
PS
Посмотрел мельком, библиотеки там правленые, просто надо внешний кварц цеплять, если нужен сериал, на RC будут проблемы
на два канала, есть возможность проверить?
/*
* Two-channel AC Dimmer for CH32V003 (single timer, two channels)
* Один детектор нуля (PD2), два канала управления симисторами.
* Канал 1: PD4 (TIM2_CH1)
* Канал 2: PD3 (TIM2_CH2)
*
* Управление через I2C (адрес 0x30):
* Регистр 0x00 — яркость канала 1 (0..255)
* Регистр 0x01 — яркость канала 2 (0..255)
* Отладка через Serial (9600 бод)
*/
#include <Wire.h>
// === Пины ===
#define ZC_PIN PD2 // вход детектора нуля (общий)
#define TRIAC1_PIN PD4 // канал 1 (TIM2_CH1)
#define TRIAC2_PIN PD3 // канал 2 (TIM2_CH2)
// === I2C адрес ===
#define I2C_ADDR 0x30
// === Переменные яркости (0..255) и задержек (0..10000 мкс) ===
volatile uint8_t pwm1 = 0;
volatile uint8_t pwm2 = 0;
volatile uint16_t delay1 = 0;
volatile uint16_t delay2 = 0;
// === Обработчик прерывания по переходу через ноль ===
void zeroCrossISR() {
// Сброс счётчика и запуск таймера
TIM2->CNT = 0;
TIM2->CTLR1 |= 0x0001; // CEN = 1
}
// === Обработчик прерывания TIM2 (общий) ===
void TIM2_IRQHandler() {
uint16_t flags = TIM2->INTFR;
// Канал 1 (совпадение CH1)
if (flags & 0x0002) { // CC1IF (бит 1)
TIM2->INTFR = 0x0002; // сброс флага
digitalWrite(TRIAC1_PIN, HIGH);
delayMicroseconds(50);
digitalWrite(TRIAC1_PIN, LOW);
// Отключаем канал, чтобы не срабатывал повторно до следующего нуля
TIM2->CCER &= ~0x0001; // CC1E = 0 (отключить выход, но можно оставить)
}
// Канал 2 (совпадение CH2)
if (flags & 0x0004) { // CC2IF (бит 2)
TIM2->INTFR = 0x0004;
digitalWrite(TRIAC2_PIN, HIGH);
delayMicroseconds(50);
digitalWrite(TRIAC2_PIN, LOW);
TIM2->CCER &= ~0x0010; // CC2E = 0 (отключить выход)
}
if (flags & 0x0001) {
TIM2->INTFR = 0x0001; // сброс
}
}
// === I2C приём ===
void receiveEvent(int howMany) {
if (howMany > 0) {
uint8_t reg = Wire.read();
if (howMany > 1) {
uint8_t val = Wire.read();
switch (reg) {
case 0x00:
pwm1 = val;
delay1 = map(pwm1, 0, 255, 0, 10000);
break;
case 0x01:
pwm2 = val;
delay2 = map(pwm2, 0, 255, 0, 10000);
break;
}
}
}
}
// === I2C запрос ===
void requestEvent() {
Wire.write(pwm1);
Wire.write(pwm2);
}
// === Настройка ===
void setup() {
Serial.begin(9600);
Serial.println("Two-channel dimmer (single timer) ready");
// Настройка пинов
pinMode(TRIAC1_PIN, OUTPUT);
pinMode(TRIAC2_PIN, OUTPUT);
digitalWrite(TRIAC1_PIN, LOW);
digitalWrite(TRIAC2_PIN, LOW);
pinMode(ZC_PIN, INPUT_PULLUP);
// --- Настройка TIM2 для двух каналов сравнения ---
RCC->APB1PCENR |= RCC_APB1Periph_TIM2;
// Базовые настройки таймера: счёт до 10000, один тик = 1 мкс
TIM2->CTLR1 = 0x0084; // ARPE=1, URS=1 (прерывание только по переполнению, но мы используем сравнение)
TIM2->PSC = 47; // 48 МГц / 48 = 1 МГц
TIM2->ATRLR = 10000; // период 10 мс
TIM2->CNT = 0;
TIM2->DMAINTENR |= 0x0006; // UIE? нет, CC1IE=бит1, CC2IE=бит2
// Устанавливаем регистры сравнения (начальные значения - 0, чтобы ничего не срабатывало)
TIM2->CH1CVR = 0;
TIM2->CH2CVR = 0;
// Включаем выходы каналов (CCER)
TIM2->CCER = 0x0001 | 0x0010; // CC1E=1, CC2E=1 (но мы будем управлять ими в прерываниях)
// Разрешаем прерывание TIM2
NVIC_EnableIRQ(TIM2_IRQn);
NVIC_SetPriority(TIM2_IRQn, 1);
// --- Внешнее прерывание на PD2 (детектор нуля) ---
attachInterrupt(
digitalPinToInterrupt(ZC_PIN),
GPIO_Mode_IN_FLOATING,
zeroCrossISR,
EXTI_Mode_Interrupt,
EXTI_Trigger_Rising_Falling
);
// --- I2C Slave ---
Wire.begin(I2C_ADDR);
Wire.onReceive(receiveEvent);
Wire.onRequest(requestEvent);
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, HIGH);
}
// === Основной цикл (отладка через Serial) ===
void loop() {
if (Serial.available()) {
int ch = Serial.parseInt();
int val = Serial.parseInt();
if (ch >= 1 && ch <= 2 && val >= 0 && val <= 255) {
if (ch == 1) {
pwm1 = val;
delay1 = map(pwm1, 0, 255, 0, 10000);
Serial.print("Channel1 brightness: ");
} else {
pwm2 = val;
delay2 = map(pwm2, 0, 255, 0, 10000);
Serial.print("Channel2 brightness: ");
}
Serial.println(val);
} else {
Serial.println("Usage: <ch> <val> e.g. '1 128'");
}
}
delay(100);
}
Ари кортекс - это только CPU, при этом объем памяти, включая ее разделение на разные сегменты, а также состав, карта портов ввода/вывода, а тем более назначение отдельных битов никакого отношения к арм кортекс не имеют. Соответственно, способы прошивки и ее извлечения - также.
И, кстати, stm32 - это не обязательно эм-ноль, могут быть и другие “эм” вплоть до эм-семь.