RGB water lamp.

This commit is contained in:
dxl
2023-02-22 18:32:27 +08:00
parent 9c44ab00b0
commit deeec029e3
9 changed files with 406 additions and 18 deletions
+2 -1
View File
@@ -15,7 +15,7 @@ $(OUTPUT_DIRECTORY)/application.out: \
CHAMELEON_ULTRA := ultra
CHAMELEON_LITE := lite
# What device is it?
CURRENT_DEVICE_TYPE := ${CHAMELEON_LITE}
CURRENT_DEVICE_TYPE := ${CHAMELEON_ULTRA}
# Source files common to all targets
@@ -26,6 +26,7 @@ SRC_FILES += \
$(PROJ_DIR)/ble_main.c \
$(PROJ_DIR)/rfid_main.c \
$(PROJ_DIR)/usb_main.c \
$(PROJ_DIR)/rgb_marquee.c \
$(PROJ_DIR)/bsp/bsp_delay.c \
$(PROJ_DIR)/bsp/bsp_time.c \
$(PROJ_DIR)/rfid/crc_utils.c \
+22 -1
View File
@@ -33,6 +33,8 @@ NRF_LOG_MODULE_REGISTER();
#include "syssleep.h"
#include "tag_emulation.h"
#include "usb_main.h"
#include "rgb_marquee.h"
// 定义软定时器
APP_TIMER_DEF(m_button_check_timer); // 用于按钮防抖的定时器
@@ -207,6 +209,20 @@ static void system_off_enter(void) {
ret = sd_power_ram_power_set(8, ram8_retention);
APP_ERROR_CHECK(ret);
// 关机动画
uint8_t slot = tag_emulation_get_slot();
for (uint8_t i = 0; i < RGB_LIST_NUM; i++) {
nrf_gpio_pin_clear(hw_get_led_array()[i]);
}
uint8_t dir = slot > 3 ? 1 : 0;
// TODO 实现从指定卡槽的位置跑到头的灯效
ledblink4(0,dir,7,99,75);
ledblink4(0,!dir,7,75,50);
ledblink4(0,dir,7,50,25);
ledblink4(0,!dir,7,25,0);
// 需要配置为浮空模拟输入且不上下拉的IO
uint32_t gpio_cfg_default_nopull[] = {
#if defined(PROJECT_CHAMELEON_ULTRA)
@@ -331,6 +347,7 @@ static void check_wakeup_src(void) {
/**@brief button press event process
*/
extern bool g_usb_led_marquee_enable;
static void button_press_process(void) {
// 确保AB按钮其中一个发生了点击事件
if (m_is_read_btn_press || m_is_write_btn_press) {
@@ -351,6 +368,8 @@ static void button_press_process(void) {
// 仅在新卡槽切换有效的情况下更新状态
if (slot_new != slot_now) {
tag_emulation_change_slot(slot_new, true); // 告诉模拟卡模块我们需要切换卡槽
g_usb_led_marquee_enable = false;
ledblink3(slot_now, 0, slot_new, 0); // 灯效
light_up_by_slot(); // 切换了卡槽,我们需要重新亮灯
set_slot_light_color(0); // 然后重新切换灯的颜色
}
@@ -364,7 +383,6 @@ static void button_press_process(void) {
*/
int main(void) {
hw_connect_init(); // 记得先把引脚初始化一下
log_init(); // 日志初始化
gpio_te_init(); // 初始化GPIO矩阵库
app_timers_init(); // 初始化软定时器
@@ -395,6 +413,9 @@ int main(void) {
while (1) {
// Button event process
button_press_process();
ledblink1(0, 0);
// Data pack process
data_frame_process();
// Log print process
+340
View File
@@ -0,0 +1,340 @@
#include "math.h"
#include "nrf_gpio.h"
#include "hw_connect.h"
#include "bsp_delay.h"
#include "rgb_marquee.h"
#include "bsp_time.h"
#define PWM_MAX 1000 // PWM 最大值
#define LIGHT_LEVEL_MAX 99 // 亮度级别最大值
static nrf_drv_pwm_t pwm0_ins = NRF_DRV_PWM_INSTANCE(1);
nrf_pwm_values_individual_t pwm_sequ_val;//独立模式下的PWM控制4通道的占空比
nrf_pwm_sequence_t const seq = //配置pwm输出用的结构体
{
.values.p_individual = &pwm_sequ_val,
.length = 4,
.repeats = 0,
.end_delay = 0
};
nrf_drv_pwm_config_t pwm_config = //PWM配置结构体
{
.irq_priority = APP_IRQ_PRIORITY_LOWEST,
.base_clock = NRF_PWM_CLK_1MHz,
.count_mode = NRF_PWM_MODE_UP,
.top_value = PWM_MAX,
.load_mode = NRF_PWM_LOAD_INDIVIDUAL,//4个通道用四个值
.step_mode = NRF_PWM_STEP_AUTO
};
static autotimer *timer;
void pwmout_init(void){
timer = bsp_obtain_timer(0);
nrf_drv_pwm_init(&pwm0_ins, &pwm_config, NULL);
}
void pwmout_uninit(void) {
nrfx_pwm_stop(&pwm0_ins,1);
nrfx_pwm_uninit(&pwm0_ins);
bsp_return_timer(timer);
}
// 亮度转PWM值
uint16_t get_pwmduty(uint8_t light_level){
return PWM_MAX-(PWM_MAX*pow(((double)light_level/LIGHT_LEVEL_MAX),2.2));
}
//4灯同亮度水平移动循环(不返回)
//COLOR 0-R,1-G,2-B
extern bool g_usb_connected;
extern bool g_usb_port_opened;
extern bool g_usb_led_marquee_enable;
extern void light_up_by_slot(void);
void ledblink1(uint8_t color, uint8_t dir){
static uint8_t startled = 0;
static uint8_t setled = 0;
uint32_t* led_pins_arr;
static bool is_uninited = true;
static bool wait_next = false;
//处理方向
if(dir == 0){
led_pins_arr = hw_get_led_array();
} else{
led_pins_arr = hw_get_led_reversal_array();
}
if (g_usb_connected && !g_usb_port_opened && g_usb_led_marquee_enable) {
if (is_uninited) {
//调整颜色
set_slot_light_color(color);
pwm_sequ_val.channel_0 = 1;
pwm_sequ_val.channel_1 = 1;
pwm_sequ_val.channel_2 = 1;
pwm_sequ_val.channel_3 = 1;
pwmout_init();
is_uninited = false;
wait_next = false;
bsp_set_timer(timer, 0);
}
if (wait_next) {
if (!(NO_TIMEOUT_1MS(timer, 80))) {
wait_next = false;
}
} else {
setled = startled;
for(uint8_t i=0;i<4;i++){
pwm_config.output_pins[i] = led_pins_arr[setled];
setled++;
if(setled>7)setled=0;
}
startled++;
if(startled>7)startled = 0;
nrfx_pwm_uninit(&pwm0_ins);
nrf_drv_pwm_init(&pwm0_ins, &pwm_config, NULL);
nrf_drv_pwm_simple_playback(&pwm0_ins, &seq, 1,NRF_DRV_PWM_FLAG_LOOP);
wait_next = true;
bsp_set_timer(timer, 0);
}
} else {
if (!is_uninited) {
pwmout_uninit();
light_up_by_slot();
}
is_uninited = true;
startled = 0;
setled = 0;
wait_next = false;
}
}
//4灯拖尾水平移动循环(不返回),包含尾部消失和头部缓入
//dir 0-从1卡槽到8卡槽,1-从8卡槽到1卡槽 (方向,结束点由end参数决定)
//end 要扫描的灯数量,和方向一起决定最终动画区域
void ledblink2(uint8_t color,uint8_t dir, uint8_t end){
uint8_t startled = 0;
uint8_t setled = 0;
uint8_t leds2turnon = 0;
uint8_t i = 0;
uint32_t * led_pins_arr;
//处理方向
if(dir == 0){
led_pins_arr = hw_get_led_array();
}
else{
led_pins_arr = hw_get_led_reversal_array();
}
//调整颜色
set_slot_light_color(color);
pwm_sequ_val.channel_3 = 1; //最亮的
pwm_sequ_val.channel_2 = 600;
pwm_sequ_val.channel_1 = 880;
pwm_sequ_val.channel_0 = 980;//最暗的
pwmout_init();
while(1) {
//关闭所有通道
pwm_config.output_pins[0] = NRF_DRV_PWM_PIN_NOT_USED;
pwm_config.output_pins[1] = NRF_DRV_PWM_PIN_NOT_USED;
pwm_config.output_pins[2] = NRF_DRV_PWM_PIN_NOT_USED;
pwm_config.output_pins[3] = NRF_DRV_PWM_PIN_NOT_USED;
setled = startled;
if(setled<3){//正向期间,0,1,2的时候只能点亮前几个led
//首先确定能点亮几个灯
leds2turnon = setled+1;//123
//然后设置pwm输出通道
for(i=0;i<leds2turnon;i++){
pwm_config.output_pins[3-i] = led_pins_arr[setled-i];
}
}else if (setled<=7){//正向期间,大于4小于8的时候能点亮4个led
//设置pwm输出通道
for(i=0;i<4;i++){
pwm_config.output_pins[3-i] = led_pins_arr[setled];
setled--;
}
}else if (setled>7&&setled<=10){//正向期间,8.9.10的时候只能点亮后几个led
//首先确定能点亮几个灯
leds2turnon = 11-setled;
//然后设置pwm输出通道
for(i=0;i<leds2turnon;i++){
pwm_config.output_pins[i] = led_pins_arr[setled-3+i];
}
}else{//正向期间,达到11
//什么都不干
}
//处理停止条件
if(startled>=end){
//计算需要隐藏几个灯
leds2turnon = startled-end;
//把超出去的都隐藏了
for(i=0;i<leds2turnon;i++){
pwm_config.output_pins[3-i] = NRF_DRV_PWM_PIN_NOT_USED;
}
//重新设置指定位置是最亮的
if(end <= 7){
pwm_config.output_pins[3] = led_pins_arr[end];
}
}
nrfx_pwm_uninit(&pwm0_ins);
nrf_drv_pwm_init(&pwm0_ins, &pwm_config, NULL);
nrf_drv_pwm_simple_playback(&pwm0_ins, &seq, 1,NRF_DRV_PWM_FLAG_LOOP);
bsp_delay_ms(40);
startled++;
if(startled-end>=4)break;
if(startled>11)break;
}
pwmout_uninit();
}
//切换卡槽动画
//led_up 要点亮的led
//color_led_up 要点亮的led的颜色 0-R,1-G,2-B
//led_down 要熄灭的led
//color_led_down 要熄灭的led的颜色 0-R,1-G,2-B
volatile bool callback_waiting = 0;
static void ledblink3_pwm_callback(nrfx_pwm_evt_type_t event_type){
if (event_type == NRF_DRV_PWM_EVT_FINISHED) {
callback_waiting = 1;
}
}
void ledblink3(uint8_t led_down,uint8_t color_led_up,uint8_t led_up,uint8_t color_led_down){
uint16_t light_level= 99;//led亮度值
uint32_t* led_pins = hw_get_led_array();
//先处理要熄灭的
pwm_config.output_pins[0] = led_pins[led_down];
pwm_config.output_pins[1] = NRF_DRV_PWM_PIN_NOT_USED;
pwm_config.output_pins[2] = NRF_DRV_PWM_PIN_NOT_USED;
pwm_config.output_pins[3] = NRF_DRV_PWM_PIN_NOT_USED;
pwmout_init();
while(light_level > 0){
//处理亮度
pwm_sequ_val.channel_0 = get_pwmduty(light_level);
nrfx_pwm_uninit(&pwm0_ins); //关闭pwm输出
nrf_gpio_pin_clear(led_pins[led_up]);
set_slot_light_color(color_led_down);
nrf_drv_pwm_init(&pwm0_ins, &pwm_config, ledblink3_pwm_callback);
nrf_drv_pwm_simple_playback(&pwm0_ins, &seq, 1,NRF_DRV_PWM_FLAG_LOOP);
while(callback_waiting == 0);//等待pwm模块输出完成
bsp_delay_us(1234);
callback_waiting = 0;
light_level --;
}
//处理要点亮的
pwm_config.output_pins[0] = led_pins[led_up];
pwm_config.output_pins[1] = NRF_DRV_PWM_PIN_NOT_USED;
pwm_config.output_pins[2] = NRF_DRV_PWM_PIN_NOT_USED;
pwm_config.output_pins[3] = NRF_DRV_PWM_PIN_NOT_USED;
while(light_level < 99){
//处理亮度
pwm_sequ_val.channel_0 = get_pwmduty(light_level);
nrfx_pwm_uninit(&pwm0_ins); //关闭pwm输出
nrf_gpio_pin_clear(led_pins[led_down]);
set_slot_light_color(color_led_up);
nrf_drv_pwm_init(&pwm0_ins, &pwm_config, ledblink3_pwm_callback);
nrf_drv_pwm_simple_playback(&pwm0_ins, &seq, 1,NRF_DRV_PWM_FLAG_LOOP);
while(callback_waiting == 0);//等待pwm模块输出完成
bsp_delay_us(1234);
callback_waiting = 0;
light_level ++;
}
pwmout_uninit();
}
//4灯拖尾水平移动循环(不返回),不包含尾部消失但是包含头部缓入(用于弹球类型动画)
//dir 0-从1卡槽到8卡槽,1-从8卡槽到1卡槽 (方向,结束点由end参数决定)
//end 要扫描的灯数量,和方向一起决定最终动画区域
//start_light stop_light 0-99 表示渐变亮度
void ledblink4(uint8_t color,uint8_t dir, uint8_t end,uint8_t start_light,uint8_t stop_light){
uint8_t startled = 0;
uint8_t setled = 0;
uint8_t leds2turnon = 0;
uint8_t i = 0;
uint32_t * led_pins_arr;
volatile double light_cnd;
//处理方向
if(dir == 0){
led_pins_arr = hw_get_led_array();
}
else{
led_pins_arr = hw_get_led_reversal_array();
}
//调整颜色
set_slot_light_color(color);
pwmout_init();
while(1) {
//设置亮度
//当前亮度系数
//start经过end次数达到stop
light_cnd = (((double)stop_light-(double)start_light)/end)*startled+start_light;
pwm_sequ_val.channel_3 = get_pwmduty((uint8_t)(0.99*light_cnd));//1; //最亮的
pwm_sequ_val.channel_2 = get_pwmduty((uint8_t)(0.60*light_cnd));//600;
pwm_sequ_val.channel_1 = get_pwmduty((uint8_t)(0.30*light_cnd));//880;
pwm_sequ_val.channel_0 = get_pwmduty((uint8_t)(0.01*light_cnd));//980;//最暗的
//关闭所有通道
pwm_config.output_pins[0] = NRF_DRV_PWM_PIN_NOT_USED;
pwm_config.output_pins[1] = NRF_DRV_PWM_PIN_NOT_USED;
pwm_config.output_pins[2] = NRF_DRV_PWM_PIN_NOT_USED;
pwm_config.output_pins[3] = NRF_DRV_PWM_PIN_NOT_USED;
setled = startled;
if(setled<3){//正向期间,0,1,2的时候只能点亮前几个led
//首先确定能点亮几个灯
leds2turnon = setled+1;//123
//然后设置pwm输出通道
for(i=0;i<leds2turnon;i++){
pwm_config.output_pins[3-i] = led_pins_arr[setled-i];
}
}else if (setled<=7){//正向期间,大于4小于8的时候能点亮4个led
//设置pwm输出通道
for(i=0;i<4;i++){
pwm_config.output_pins[3-i] = led_pins_arr[setled];
setled--;
}
}else if (setled>7&&setled<=10){//正向期间,8.9.10的时候只能点亮后几个led
//首先确定能点亮几个灯
leds2turnon = 11-setled;
//然后设置pwm输出通道
for(i=0;i<leds2turnon;i++){
pwm_config.output_pins[i] = led_pins_arr[setled-3+i];
}
}else{//正向期间,达到11
//什么都不干
}
//处理停止条件
if(startled==end){
break;
}
nrfx_pwm_uninit(&pwm0_ins);
nrf_drv_pwm_init(&pwm0_ins, &pwm_config, NULL);
nrf_drv_pwm_simple_playback(&pwm0_ins, &seq, 1,NRF_DRV_PWM_FLAG_LOOP);
bsp_delay_ms(50);
startled++;
if(startled-end>=4)break;
if(startled>11)break;
}
pwmout_uninit();
}
+13
View File
@@ -0,0 +1,13 @@
#ifndef RGB_MARQUEE_H
#define RGB_MARQUEE_H
#include <stdint.h>
#include "nrf_drv_pwm.h"
void ledblink1(uint8_t color,uint8_t dir);
void ledblink2(uint8_t color,uint8_t dir, uint8_t end);
void ledblink3(uint8_t led_down,uint8_t color_led_up,uint8_t led_up,uint8_t color_led_down);
void ledblink4(uint8_t color,uint8_t dir, uint8_t end,uint8_t start_light,uint8_t stop_light);
#endif
+1 -1
View File
@@ -4981,7 +4981,7 @@
#ifndef PWM1_ENABLED
#define PWM1_ENABLED 0
#define PWM1_ENABLED 1
#endif
// <q> PWM2_ENABLED - Enable PWM2 instance
+16 -9
View File
@@ -37,8 +37,9 @@ APP_USBD_CDC_ACM_GLOBAL_DEF(m_app_cdc_acm,
// USB DEFINES END
// USB CODE START
static bool m_usb_connected = false;
static bool m_usb_port_opened = false;
volatile bool g_usb_connected = false;
volatile bool g_usb_port_opened = false;
volatile bool g_usb_led_marquee_enable = false;
/** @brief User event handler @ref app_usbd_cdc_acm_user_ev_handler_t */
static void cdc_acm_user_ev_handler(app_usbd_class_inst_t const *p_inst, app_usbd_cdc_acm_user_event_t event) {
@@ -56,15 +57,14 @@ static void cdc_acm_user_ev_handler(app_usbd_class_inst_t const *p_inst, app_usb
ret_code_t ret = app_usbd_cdc_acm_read(&m_app_cdc_acm, cdc_data_buffer, 1);
UNUSED_VARIABLE(ret);
NRF_LOG_INFO("CDC ACM port opened");
m_usb_port_opened = true;
g_usb_port_opened = true;
break;
}
case APP_USBD_CDC_ACM_USER_EVT_PORT_CLOSE:
NRF_LOG_INFO("CDC ACM port closed");
m_usb_port_opened = false;
if (m_usb_connected) {
}
g_usb_port_opened = false;
g_usb_led_marquee_enable = true;
break;
case APP_USBD_CDC_ACM_USER_EVT_TX_DONE:
@@ -91,15 +91,19 @@ static void cdc_acm_user_ev_handler(app_usbd_class_inst_t const *p_inst, app_usb
static void usbd_user_ev_handler(app_usbd_event_type_t event) {
switch (event) {
case APP_USBD_EVT_DRV_SUSPEND:
NRF_LOG_INFO("USB SUSPEND");
break;
case APP_USBD_EVT_DRV_RESUME:
NRF_LOG_INFO("USB RESUME");
break;
case APP_USBD_EVT_STARTED:
NRF_LOG_INFO("USB STARTED");
break;
case APP_USBD_EVT_STOPPED:
NRF_LOG_INFO("USB STOPPED");
app_usbd_disable();
break;
@@ -109,22 +113,25 @@ static void usbd_user_ev_handler(app_usbd_event_type_t event) {
if (!nrf_drv_usbd_is_enabled()) {
app_usbd_enable();
}
g_usb_led_marquee_enable = true;
break;
case APP_USBD_EVT_POWER_REMOVED:
sleep_timer_start(SLEEP_DELAY_MS_USB_POWER_DISCONNECTED);
NRF_LOG_INFO("USB power removed");
m_usb_connected = false;
g_usb_connected = false;
g_usb_led_marquee_enable = false;
app_usbd_stop();
break;
case APP_USBD_EVT_POWER_READY:
NRF_LOG_INFO("USB ready");
m_usb_connected = true;
g_usb_connected = true;
app_usbd_start();
break;
default:
// NRF_LOG_INFO("Other usb event: %d", event);
break;
}
}
@@ -158,7 +165,7 @@ int fputc(int ch, FILE *f){
ch_static = ch;
// must cdc is available
if (m_usb_port_opened && m_usb_connected) {
if (g_usb_port_opened && g_usb_connected) {
// send and wait done.
ret_code_t ret;
do {
+1 -1
View File
@@ -16,7 +16,7 @@ $(OUTPUT_DIRECTORY)/bootloader.out: \
CHAMELEON_ULTRA := ultra
CHAMELEON_LITE := lite
# What device is it?
CURRENT_DEVICE_TYPE := ${CHAMELEON_LITE}
CURRENT_DEVICE_TYPE := ${CHAMELEON_ULTRA}
# Source files common to all targets
+10 -4
View File
@@ -49,10 +49,12 @@ uint32_t g_reader_power;
uint32_t m_led_array[MAX_LED_NUM];
#define INIT_LED_ARRAY(num, led) \
if (RGB_LIST_NUM >= num) { \
m_led_array[num - 1] = led; \
} \
uint32_t m_led_reversal_array[MAX_LED_NUM];
#define INIT_LED_ARRAY(num, led) \
if (RGB_LIST_NUM >= num) { \
m_led_array[num - 1] = led; \
m_led_reversal_array[RGB_LIST_NUM - num] = led; \
} \
uint32_t m_rgb_array[MAX_RGB_NUM];
@@ -220,6 +222,10 @@ uint32_t* hw_get_led_array(void) {
return m_led_array;
}
uint32_t* hw_get_led_reversal_array(void) {
return m_led_reversal_array;
}
uint32_t* hw_get_rgb_array(void) {
return m_rgb_array;
}
+1 -1
View File
@@ -7,7 +7,6 @@
#include "nrf_lpcomp.h"
#include "device_info.h"
typedef enum {
CHAMELEON_ULTRA,
CHAMELEON_LITE,
@@ -92,6 +91,7 @@ extern uint32_t g_reader_power;
void hw_connect_init(void);
void init_leds(void);
uint32_t* hw_get_led_array(void);
uint32_t* hw_get_led_reversal_array(void);
uint32_t* hw_get_rgb_array(void);
chameleon_device_type_t hw_get_device_type(void);
uint8_t hw_get_version_code(void);