STM32F103C8T6作为MODBUS从机驱动WS2812B
终于实现了:
1、STM32F103C8T6驱动WS2812B;
2、通过Modbus协议给STM32F103C8T6发送指令,设置WS2812B显示方式;
显示方式有:
方向:正向 反向
模式:常亮 流水(正反显) 跑马(正反显) 两种颜色过渡跑马 单段亮度阶梯流水 呼吸
颜色:有(黑、白、红、绿、蓝、黄、紫、青)8种预设,颜色9为自定义,可以自由定义
3、2025-2-20更新,增加了将收到参数存入FLASH,重启后判断是刷机后重启还是正常重启,正常重启从FLASH读取上次的参数运行;
4、2025-2-20更新,增加了IWDG,防止死机,死机后自动重启,并用上次的参数直接运行;
5、通过GPIO灵活设置STM32F103C8T6从机地址。
6、2025-2-20更新,增加RS485通信模块,
测试通过了上位机-UART-RS485-RS485-UART-F103 的数据发送与接收。
先记录一下,回头慢慢完善帖子。
工程文件如下(stm32cubeMX、MDK),这是旧的,其实都是stm32cubeMX生成的,就懒得上传新的了,关键的自己写的main.h、main.c完整的贴到最后,共同好一起研究:
【免费】STM32F103C8T6作为MODBUS从机驱动WS2812B资源-优快云文库
买过两种WS2812B的灯带,发现有所不同。
一种是“G-R-B”的数据顺序,一种是“R-G-B”的数据顺序。
根据情况,调整这一段代码,对应的“red”和“green”即可。
2025-2-20更新,解决了C6T6内部RAM小的问题:
/*二维数组存放最终PWM输出数组,每一行24个数据代表一个LED,最后一行24个0代表RESET码*/
uint16_t Pixel_Buf[141][24];
用uint16_t 存储每个灯的颜色参数,同时PWM的DMA发送选“HALFWORD”如下,这样在140灯的情况下,RAM占用刚好小于10240(10K),实测裸板C6T6跑起来了;
2025-2-20上午更新,为了进一步减少RAM占用,增加灯的数量,用 uint8_t 和 “BYTE” 试了,但是没有成功,以后再研究。
void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef* tim_pwmHandle)
{
if(tim_pwmHandle->Instance==TIM2)
{
/* USER CODE BEGIN TIM2_MspInit 0 */
/* USER CODE END TIM2_MspInit 0 */
/* TIM2 clock enable */
__HAL_RCC_TIM2_CLK_ENABLE();
/* TIM2 DMA Init */
/* TIM2_CH3 Init */
hdma_tim2_ch3.Instance = DMA1_Channel1;
hdma_tim2_ch3.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_tim2_ch3.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_tim2_ch3.Init.MemInc = DMA_MINC_ENABLE;
hdma_tim2_ch3.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
hdma_tim2_ch3.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
hdma_tim2_ch3.Init.Mode = DMA_NORMAL;
hdma_tim2_ch3.Init.Priority = DMA_PRIORITY_LOW;
if (HAL_DMA_Init(&hdma_tim2_ch3) != HAL_OK)
{
Error_Handler();
}
__HAL_LINKDMA(tim_pwmHandle,hdma[TIM_DMA_ID_CC3],hdma_tim2_ch3);
/* USER CODE BEGIN TIM2_MspInit 1 */
/* USER CODE END TIM2_MspInit 1 */
}
}
Keil 编译后的存储占用情况
Program Size: Code=14676 RO-data=312 RW-data=140 ZI-data=10020
RAM=RW-data+ZI-data=140+10020=10160<10240(10k)
2025-2-20下午更新,今天真是个好日子,中午刚写了用 uint8_t 和 “BYTE” 下午就无意中找到一篇文章,测试通过了 。参考以下文章:
STM32 G431RB 中实现对WS2812灯带的控制(PWM + DMA) - magicduan - 博客园
内存用“byte”这样就省了RAM,给外设发送的时候用“HalfWord”,就没问题了。
同时为了对齐,定义buff的时候如下:
/*二维数组存放最终PWM输出数组,每一行24个数据代表一个LED,最后一行24个0代表RESET码*/
#define DMA_TYPE uint8_t
__attribute__((aligned(4))) volatile DMA_TYPE Pixel_Buf[281][24];
281灯编译程序后存储占用如下:
Program Size: Code=14672 RO-data=312 RW-data=140 ZI-data=9996
RAM=RW-data+ZI-data=140+9996=10136<10240(10k)
O(∩_∩)O哈哈~O(∩_∩)O哈哈~O(∩_∩)O哈哈~O(∩_∩)O哈哈~O(∩_∩)O哈哈~
谢谢:
205-2-21更新:又深入的研究了一下代码,发现RAM占用还有潜力可挖,如下图main.h这段代码:
如果主机从机通讯的数据量很小,我的就是点儿配置数据,加上ModBus的协议字段,也就不超过30byte,这个几个数组可以整的更小,腾出更多的RAM给灯的数据用,还可以增加灯的数量,这里指提出思路,就不再测试了。
2025-2-20更新,解决了收到数据后进不到DMA空闲中断的问题:
参考的这个帖子:HAL库 串口空闲中断+DMA接收不定长数据 详解及踩坑_hal库串口空闲中断-优快云博客
HAL_UARTEx_ReceiveToIdle_DMA(&huart1, xUSART1.BuffTemp, sizeof(xUSART1.BuffTemp)); //开启DMA空闲中断
千万不要将上面的 “重新开启DMA空闲中断” 放在中断处理回调函数里
/*************************************************************************************************************
功能:usart接收中断处理函数
*************************************************************************************************************/
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
if (huart == &huart1) { // 判断串口
__HAL_UNLOCK(huart); // 解锁串口状态
xUSART1.receiveNUM = Size; // 把接收字节数,存入结构体xUSART1.ReceiveNum
memset(Modbus.receive, 0, sizeof(Modbus.receive)); // 清除Modbus.receive前一帧接收到的数据
memset(xUSART1.receiveData, 0, sizeof(xUSART1.receiveData)); // 清除xUSART1.ReceiveData前一帧接收到的数据
memcpy(xUSART1.receiveData, xUSART1.BuffTemp, Size); // 把新数据,从临时缓存中,复制到xUSART1.ReceiveData[]
memcpy(Modbus.receive, xUSART1.BuffTemp, Size); // 把新数据,从临时缓存中,复制到Modbus.receive
// 再次开启DMA空闲中断;不要放在这里,会出现开启不了的可能,应放到中断处理函数里
//HAL_UARTEx_ReceiveToIdle_DMA(&huart1, xUSART1.BuffTemp,sizeof(xUSART1.BuffTemp));
}
}
而应放到 stm32f1xx_it.c 中断处理函数里:
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
HAL_UARTEx_ReceiveToIdle_DMA(&huart1, xUSART1.BuffTemp,sizeof(xUSART1.BuffTemp));
// 再次开启DMA空闲中断; 一定要放在这里,否则可能会无法再次打开
/* USER CODE END USART1_IRQn 1 */
}
经过不断修改又加了一些显示方式,就不修改上传的工程了,把最新的main.h、main.c直接贴出来:
main.h
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.h
* @brief : Header for main.c file.
* This file contains the common defines of the application.
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __MAIN_H
#define __MAIN_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_hal.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "stdbool.h"
/*这里是上文计算所得CCR的宏定义*/
#define CODE_1 (58) //1码定时器计数次数
#define CODE_0 (28) //0码定时器计数次数
/*建立一个定义单个LED三原色值大小的结构体*/
typedef struct {
uint8_t number; //颜色序号
uint8_t red; //红
uint8_t green; //绿
uint8_t blue; //蓝
} color_map_TypeDef;
/* 声明modbus的结构体 */
typedef struct {
uint8_t address; /* 从机基地址 */
uint8_t send[100]; /* 发送缓冲区 C8T6 100*/
uint8_t receive[100]; /* 接收缓冲区 C8T6 100*/
} modbus_TypeDef;
extern modbus_TypeDef Modbus; /* 声明modbus的结构体 */
typedef struct { /* 声明一个变量,用于管理变量 */
uint16_t receiveNUM; /* 接收字节数;在中段回调函数里被自动赋值;8>0即为接收到的第一帧 */
uint8_t receiveData[512]; /* 接受到的数据 C8T6 512 */
uint8_t BuffTemp[512]; /* 接收缓存;C8T6 512接收到一帧的时候就会清零并(一帧)复制到ReceivedData[ ] */
} xUSARTx_TypeDef;
/* 声明串口结构体 */
extern xUSARTx_TypeDef xUSART1; /* 声明串口1的结构体 */
/* 声明WB2812相关函数 */
void Reset_Load(void); //该函数用于将数组最后24个数据变为0,代表RESET_code
void RGB_SendArray(void); //发送最终数组
void RGB_RESET(uint16_t Pixel_Len); //数据全部清零
void RGB_SetColor(uint16_t LedId, color_map_TypeDef Color); //给一个LED装载24个颜色数据码(0码和1码)
void RGB_SetnColor(uint16_t LedSrart, uint16_t LedNumber, color_map_TypeDef Color); //给n个LED装载24个颜色数据码(0码和1码)
void RGB_COLOR(uint16_t Pixel_Len, color_map_TypeDef Color); //指定长度LED显示指定颜色
void rgb_strip_f(uint16_t Pixel_Len, uint16_t Step, color_map_TypeDef Color); //指定长度LED显示指定颜色正向流水灯
void rgb_strip_f_rsv(uint16_t Pixel_Len, uint16_t Step, color_map_TypeDef Color); //指定长度LED显示指定颜色"反显"正向流水灯
void rgb_strip_b(uint16_t Pixel_Len, uint16_t Step, color_map_TypeDef Color); //指定长度LED显示指定颜色反向流水灯
void rgb_strip_b_rsv(uint16_t Pixel_Len, uint16_t Step, color_map_TypeDef Color); //指定长度LED显示指定颜色"反显"反向流水灯
void rgb_run_f(uint16_t Pixel_Len, uint16_t Pixel_Num, color_map_TypeDef Color); //指定长度LED显示指定颜色正向跑马灯
void rgb_run_f_rsv(uint16_t Pixel_Len, uint16_t Pixel_Num, color_map_TypeDef Color); //指定长度LED显示指定颜色"反显"正向跑马灯
void rgb_run_b(uint16_t Pixel_Len, uint16_t Pixel_Num, color_map_TypeDef Color); //指定长度LED显示指定颜色反向跑马灯
void rgb_run_b_rsv(uint16_t Pixel_Len, uint16_t Pixel_Num, color_map_TypeDef Color); //指定长度LED显示指定颜色"反显"反向跑马灯
void Set_Color_Trans(color_map_TypeDef color_1, color_map_TypeDef color_2, uint16_t len_color1, uint16_t len_in,
uint16_t len_color2); //分段颜色转换设置,第一段-过渡-第三段
void rgb_run_f_trans_rsv(color_map_TypeDef color_1, color_map_TypeDef color_2, uint16_t Pixel_Len, uint16_t Step, uint16_t len_color1,
uint16_t len_color2);//正向分段颜色转换“反显”跑马,第一段-过渡-第三段
void rgb_run_b_trans_rsv(color_map_TypeDef color_1, color_map_TypeDef color_2, uint16_t Pixel_Len, uint16_t Step, uint16_t len_color1,
uint16_t len_color2);//反向分段颜色转换“反显”跑马,第一段-过渡-第三段
void rgb_strip_trans(color_map_TypeDef color,uint16_t Pixel_Len,uint16_t Step);//按步长明暗渐变流水
void rgb_strip_trans_rsv(color_map_TypeDef color, uint16_t Pixel_Len, uint16_t Step);//按步长明暗渐变反向流水
void rgb_run_breathe(color_map_TypeDef color, uint16_t Pixel_Len, uint16_t Step); //亮-灭-亮 呼吸灯
void rgb_run_breathe_rsv(color_map_TypeDef color, uint16_t Pixel_Len, uint16_t Step); //灭-亮-灭 呼吸灯
bool flashWriteData(int paramSizeKb, uint16_t data[], size_t len);
void flashReadData(int paramSizeKb, uint16_t *data, size_t len);
/* 声明modbus的相关函数 */
void Modbus_Init(void); //初始化modbus
void Modbus_processing(void); //modbus命令处理主程序
void Function_03(void); //modbus03命令处理程序
void Function_06(void); //modbus06命令处理程序
void Function_16(void); //modbus16命令处理程序
uint16_t Modbus_CRC16(uint8_t *buffer, uint16_t buffer_length); //modbusCRC-16处理程序
/* 声明求最大最小值相关函数 */
uint8_t max(uint8_t a, uint8_t b);
uint8_t min(uint8_t a, uint8_t b);
/* USER CODE END Includes */
/* Exported types ------------------------------------------------------------*/
/* USER CODE BEGIN ET */
/* USER CODE END ET */
/* Exported constants --------------------------------------------------------*/
/* USER CODE BEGIN EC */
/* USER CODE END EC */
/* Exported macro ------------------------------------------------------------*/
/* USER CODE BEGIN EM */
/* USER CODE END EM */
/* Exported functions prototypes ---------------------------------------------*/
void Error_Handler(void);
/* USER CODE BEGIN EFP */
/* USER CODE END EFP */
/* Private defines -----------------------------------------------------------*/
/* USER CODE BEGIN Private defines */
/* USER CODE END Private defines */
#ifdef __cplusplus
}
#endif
#endif /* __MAIN_H */
main.c
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "dma.h"
#include "iwdg.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
//https://blog.youkuaiyun.com/2402_84849283/article/details/142520108?spm=1001.2014.3001.5506
#include "stdio.h"
#include <string.h>
#include <stdint.h>
#include "stdbool.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
#define PAGE_START_ADDRESS 0x8000000
#define PARA_SIZE 26
/* 定义一些变量 */
uint16_t LED_NUM = 160; //定义LED数量
uint16_t LED_STEP_n = 5; //定义跑马灯长度
//
uint16_t LED_DIRECT = 0; //定义运行方向,0正向,1反向
uint16_t LED_MOD = 0; //定义模式,0全亮,1,流水,2跑马
//
uint8_t LED_COLOR1 = 0; //定义灯颜色,0-7为预设(黑、白、红、绿、蓝、黄、青、紫,8可以自行设定颜色
uint8_t LED_COLOR2 = 0; //定义灯颜色,0-7为预设(黑、白、红、绿、蓝、黄、青、紫,8可以自行设定颜色
//
uint8_t LED_LIGHT = 0; //定义预设颜色的亮度
uint16_t delay_ms = 8; //定义跑马灯正常的时间间隔
//
uint8_t red1 = 0; //定义自设定灯颜色 红1
uint8_t red2 = 0; //定义自设定灯颜色 红2
//
uint8_t green1 = 0; //定义自设定灯颜色 绿1
uint8_t green2 = 0; //定义自设定灯颜色 绿2
//
uint8_t blue1 = 0; //定义自设定灯颜色 蓝1
uint8_t blue2 = 0; //定义自设定灯颜色 蓝2
//
uint16_t LEN_1 = 5; //定义过渡色第一段
uint16_t LEN_2 = 8; //定义过渡色第三段
/*呼吸灯暂未调通*/
uint16_t BRTH_STEP = 5; //定义呼吸灯步长
uint8_t BREATHE_MAX = 0; //定义呼吸灯的颜色最大值
uint8_t BREATHE_MIN = 0; //定义呼吸灯的颜色最小值
/*二维数组存放最终PWM输出数组,每一行24个数据代表一个LED,最后一行24个0代表RESET码*/
#define DMA_TYPE uint8_t
__attribute__((aligned(4))) volatile DMA_TYPE Pixel_Buf[281][24];
//uint16_t Pixel_Buf[161][24];
/*
如果使用uint8_t
在tim.c 中 hdma_tim2_ch3.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
hdma_tim2_ch3.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
占用内存为 Buf 的大小 161*24
如果使用uint16_t
在tim.c 中 hdma_tim2_ch3.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
hdma_tim2_ch3.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
占用内存为 Buf 的大小 161*24*2
如果使用uint32_t
在tim.c 中 hdma_tim2_ch3.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
hdma_tim2_ch3.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
占用内存为 Buf 的大小 161*24*4
外设必须为 HALFWORD 或 WORD,内存可以 WORD HALFWORD BYTE,BYTE的话必须如上对齐,其他不必要。
*/
/* 定义颜色结构体数组 */
color_map_TypeDef color_list[9] = { //预制8种颜色,第9种可以通过指令自行设定
{0, 0, 0, 0}, //预制黑色
{1, 255, 255, 255}, //预制白色
{2, 255, 0, 0}, //预制红色
{3, 0, 255, 0}, //预制绿色
{4, 0, 0, 255}, //预制蓝色
{5, 255, 255, 0}, //预制黄色
{6, 0, 255, 255}, //预制青色
{7, 255, 0, 255}, //预制紫色
{8, 255, 255, 255}, //用于自由设定颜色
};
/* modbus寄存器数据 */
uint16_t Reg[] = {0x1403, /*0 fff 灯带长度 | f 跑马灯步长 */
0x0002, /*1 ff 方向(0,正向;1,反向 | ff 模式(0,全亮;1,流水;2,跑马;3,反显流水;4,反显跑马;反显过度色*/
0x0203, /*2 ff 标准颜色1 | ff 标准颜色2*/
0x3508, /*3 ff 标准颜色亮度 | ff 正常时延 */
0x0000, /*4 ff 自定义红1 | ff 自定义红2*/
0x0001, /*5 ff 自定义绿1 | ff 自定义绿2*/
0x0900, /*6 ff 自定义蓝1 | ff 自定义蓝2*/
0X0000, /*7 ff 第一段长度 | ff 第二段长度*/
0XF0F0 /*7 ffff 读取flash校验 */
};
uint16_t readData[9] = {0xA003, 0x0002, 0x0203, 0xc808, 0x0011, 0x1100, 0x3535, 0x2020, 0x00BB};
xUSARTx_TypeDef xUSART1; //定义USART结构体
modbus_TypeDef Modbus; //定义Modbus结构体
color_map_TypeDef color_1 = {0, 0, 0, 0};
color_map_TypeDef color_2 = {0, 0, 0, 0};
#pragma import(__use_no_semihosting)
struct __FILE {
int handle;
}; // 标准库需要的支持函数
FILE __stdout; // FILE 在stdio.h文件
void _sys_exit(int x)
{
x = x; // 定义_sys_exit()以避免使用半主机模式
}
int fputc(int ch, FILE *f) // 重写fputc函数,使printf的输出由UART1实现, 这里使用USART1
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0x02);
return ch;
}
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_TIM2_Init();
MX_USART1_UART_Init();
MX_IWDG_Init();
/* USER CODE BEGIN 2 */
//uint16_t color_len = sizeof(color_list) / sizeof(color_list[0]);
Modbus_Init(); //初始化Modbus地址代码
/*************************************************************************************************************
下面是三种发送方式
*发送方式1:阻塞式发送
*发送方式2:中断式发送
*发送方式3:DMA发送
*************************************************************************************************************/
static char Example [] = "Hello World!\r\n"; //定义一个数组
HAL_UART_Transmit(&huart1, (uint8_t *)Example, strlen(Example), 0xFFFF); //方式1
HAL_UART_Transmit_IT(&huart1, (uint8_t *)Example, strlen(Example)); //方式2
while ((&huart1)->gState != HAL_UART_STATE_READY); //等待中断式发送完成
HAL_UART_Transmit_DMA(&huart1, (uint8_t *)Example, strlen(Example)); //方式3
HAL_UARTEx_ReceiveToIdle_DMA(&huart1, xUSART1.BuffTemp, sizeof(xUSART1.BuffTemp)); //开启DMA空闲中断
flashReadData(PARA_SIZE, readData, 9);
if (readData[8] == 61680) {
for (int i = 0; i < 9; i++) {
Reg[i] = readData[i];
}
} else {
}
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1) {
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET); //系统监视灯
/*USART 接收 Modbus 处理*/
if (xUSART1.receiveNUM) { // 判断字节数
//printf("\r<<<<< USART1 接收到一帧数据 \r"); // 提示
//printf("ASCII : %s\r", (char *)xUSART1.receiveData); // 显示数据,以ASCII方式显示,即以字符串的方式显示
// printf("字节数:%d \r", xUSART1.receiveNUM); // 显示字节数
//printf("\r\r");
Modbus_processing(); // Modbus命令处理主程序
xUSART1.receiveNUM = 0; // 清0接收标记
}
/***********000***********************************************************************************************/
LED_NUM = (Reg[0] >> 8) & 0x0FFF;
if (LED_NUM>320){
LED_NUM=320;
} //获取 LED 长度
LED_STEP_n = Reg[0] & 0x000F; //获取 LED 跑马灯步长
/***********111***********************************************************************************************/
LED_DIRECT = (Reg[1] >> 8) & 0x00FF; //获取 LED 方向
LED_MOD = Reg[1] & 0x00FF; //获取 LED 模式
if (LED_DIRECT > 1) {
LED_DIRECT = 0; //方向超出范围,置为正向
}
if (LED_MOD > 7) {
LED_MOD = 0; //模式超出范围,置为全亮,模式0
}
/*********222*************************************************************************************************/
LED_COLOR1 = (uint8_t)(Reg[2] >> 8); //获取 LED 标准颜色1序号
LED_COLOR2 = (uint8_t)(Reg[2]); //获取 LED 标准颜色2序号
/********333**************************************************************************************************/
LED_LIGHT = (uint8_t)(Reg[3] >> 8); //获取 LED 亮度
delay_ms = Reg[3] & 0x00FF; //获取 LED 时延
/*******444***************************************************************************************************/
red1 = (uint8_t)(Reg[4] >> 8); //获取 LED 时延
red2 = (uint8_t)(Reg[4]); //获取 LED 自选 红色亮度
/********555**************************************************************************************************/
green1 = (uint8_t)(Reg[5] >> 8); //获取 LED 时延
green2 = (uint8_t)(Reg[5]); //获取 LED 自选 红色亮度
/*********666*************************************************************************************************/
blue1 = (uint8_t)(Reg[6] >> 8); //获取 LED 时延
blue2 = (uint8_t)(Reg[6]); //获取 LED 自选 红色亮度
/********777**************************************************************************************************/
LEN_1 = (Reg[7] >> 8) & 0x00FF; //获取 流水灯步长
LEN_2 = Reg[7] & 0x00FF; //获取 呼吸灯步长
/*************************************************************************************************************/
if (LED_COLOR1 == 8) {
color_1.red = red1; //设定 LED 自选1 红色亮度
color_1.green = green1; //设定 LED 自选1 绿色亮度
color_1.blue = blue1; //设定 LED 自选1 蓝色亮度
} else if (LED_COLOR1 < 8) {
color_1.red = color_list[LED_COLOR1].red &LED_LIGHT; //设定 LED 红色亮度
color_1.green = color_list[LED_COLOR1].green &LED_LIGHT; //设定 LED 绿色亮度
color_1.blue = color_list[LED_COLOR1].blue &LED_LIGHT; //设定 LED 蓝色亮度
} else {
color_1.red = 0; //超出颜色数量范围全置零
color_1.green = 0; //超出颜色数量范围全置零
color_1.blue = 0; //超出颜色数量范围全置零
}
if (LED_COLOR2 == 8) {
color_2.red = red2; //设定 LED 自选2 红色亮度
color_2.green = green2; //设定 LED 自选2 绿色亮度
color_2.blue = blue2; //设定 LED 自选2 蓝色亮度
} else if (LED_COLOR2 < 8) {
color_2.red = color_list[LED_COLOR2].red &LED_LIGHT; //设定 LED 红色亮度
color_2.green = color_list[LED_COLOR2].green &LED_LIGHT; //设定 LED 绿色亮度
color_2.blue = color_list[LED_COLOR2].blue &LED_LIGHT; //设定 LED 蓝色亮度
} else {
color_2.red = 0; //超出颜色数量范围全置零
color_2.green = 0; //超出颜色数量范围全置零
color_2.blue = 0; //超出颜色数量范围全置零
}
//判断方向功能码
if (LED_DIRECT == 0) { //判断方向功能码正向
//判断模式功能码
if (LED_MOD == 0) { //判断模式功能码 全亮
HAL_NVIC_DisableIRQ(DMA1_Channel4_IRQn); //关闭串口DMA通道,以便DMA发送WS2812数据 经测试,这些关闭打开没有也可以运行,以后再深入研究,当时是无法在 驱动WS2812事printf,所以加了这些打开关闭
HAL_NVIC_DisableIRQ(DMA1_Channel5_IRQn); //关闭串口DMA通道,以便DMA发送WS2812数据
HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn); //开启WS2812用DMA通道,以便DMA发送WS2812数据
RGB_COLOR(LED_NUM, color_1);
HAL_NVIC_DisableIRQ(DMA1_Channel1_IRQn); //关闭WS2812DMA通道,以便DMA发送串口数据
HAL_NVIC_EnableIRQ(DMA1_Channel4_IRQn); //开启串口用DMA通道,以便DMA发送串口数据
HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn); //开启串口用DMA通道,以便DMA发送串口数据
} else if (LED_MOD == 1) { //判断模式功能码 流水灯
HAL_NVIC_DisableIRQ(DMA1_Channel4_IRQn); //关闭串口DMA通道,以便DMA发送WS2812数据
HAL_NVIC_DisableIRQ(DMA1_Channel5_IRQn); //关闭串口DMA通道,以便DMA发送WS2812数据
HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn); //开启WS2812用DMA通道,以便DMA发送WS2812数据
rgb_strip_f(LED_NUM, LED_STEP_n, color_1);
HAL_NVIC_DisableIRQ(DMA1_Channel1_IRQn); //关闭WS2812DMA通道,以便DMA发送串口数据
HAL_NVIC_EnableIRQ(DMA1_Channel4_IRQn); //开启串口用DMA通道,以便DMA发送串口数据
HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn); //开启串口用DMA通道,以便DMA发送串口数据
} else if (LED_MOD == 2) { //判断模式功能码 跑马灯
HAL_NVIC_DisableIRQ(DMA1_Channel4_IRQn); //关闭串口DMA通道,以便DMA发送WS2812数据
HAL_NVIC_DisableIRQ(DMA1_Channel5_IRQn); //关闭串口DMA通道,以便DMA发送WS2812数据
HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn); //开启WS2812用DMA通道,以便DMA发送WS2812数据
rgb_run_f(LED_NUM, LED_STEP_n, color_1);
HAL_NVIC_DisableIRQ(DMA1_Channel1_IRQn); //关闭WS2812DMA通道,以便DMA发送串口数据
HAL_NVIC_EnableIRQ(DMA1_Channel4_IRQn); //开启串口用DMA通道,以便DMA发送串口数据
HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn); //开启串口用DMA通道,以便DMA发送串口数据
} else if (LED_MOD == 3) { //判断模式功能码 流水灯
HAL_NVIC_DisableIRQ(DMA1_Channel4_IRQn); //关闭串口DMA通道,以便DMA发送WS2812数据
HAL_NVIC_DisableIRQ(DMA1_Channel5_IRQn); //关闭串口DMA通道,以便DMA发送WS2812数据
HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn); //开启WS2812用DMA通道,以便DMA发送WS2812数据
rgb_strip_f_rsv(LED_NUM, LED_STEP_n, color_1);
HAL_NVIC_DisableIRQ(DMA1_Channel1_IRQn); //关闭WS2812DMA通道,以便DMA发送串口数据
HAL_NVIC_EnableIRQ(DMA1_Channel4_IRQn); //开启串口用DMA通道,以便DMA发送串口数据
HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn); //开启串口用DMA通道,以便DMA发送串口数据
} else if (LED_MOD == 4) { //判断模式功能码 跑马灯
HAL_NVIC_DisableIRQ(DMA1_Channel4_IRQn); //关闭串口DMA通道,以便DMA发送WS2812数据
HAL_NVIC_DisableIRQ(DMA1_Channel5_IRQn); //关闭串口DMA通道,以便DMA发送WS2812数据
HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn); //开启WS2812用DMA通道,以便DMA发送WS2812数据
rgb_run_f_rsv(LED_NUM, LED_STEP_n, color_1);
HAL_NVIC_DisableIRQ(DMA1_Channel1_IRQn); //关闭WS2812DMA通道,以便DMA发送串口数据
HAL_NVIC_EnableIRQ(DMA1_Channel4_IRQn); //开启串口用DMA通道,以便DMA发送串口数据
HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn); //开启串口用DMA通道,以便DMA发送串口数据
} else if (LED_MOD == 5) { //判断模式功能码 呼吸灯
HAL_NVIC_DisableIRQ(DMA1_Channel4_IRQn); //关闭串口DMA通道,以便DMA发送WS2812数据
HAL_NVIC_DisableIRQ(DMA1_Channel5_IRQn); //关闭串口DMA通道,以便DMA发送WS2812数据
HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn); //开启WS2812用DMA通道,以便DMA发送WS2812数据
rgb_run_f_trans_rsv(color_1, color_2, LED_NUM, LED_STEP_n, LEN_1, LEN_2);
HAL_NVIC_DisableIRQ(DMA1_Channel1_IRQn); //关闭WS2812DMA通道,以便DMA发送串口数据
HAL_NVIC_EnableIRQ(DMA1_Channel4_IRQn); //开启串口用DMA通道,以便DMA发送串口数据
HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn); //开启串口用DMA通道,以便DMA发送串口数据
} else if (LED_MOD == 6) { //判断模式功能码 呼吸灯
HAL_NVIC_DisableIRQ(DMA1_Channel4_IRQn); //关闭串口DMA通道,以便DMA发送WS2812数据
HAL_NVIC_DisableIRQ(DMA1_Channel5_IRQn); //关闭串口DMA通道,以便DMA发送WS2812数据
HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn); //开启WS2812用DMA通道,以便DMA发送WS2812数据
rgb_strip_trans(color_1, LED_NUM, LED_STEP_n);
HAL_NVIC_DisableIRQ(DMA1_Channel1_IRQn); //关闭WS2812DMA通道,以便DMA发送串口数据
HAL_NVIC_EnableIRQ(DMA1_Channel4_IRQn); //开启串口用DMA通道,以便DMA发送串口数据
HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn); //开启串口用DMA通道,以便DMA发送串口数据
} else if (LED_MOD == 7) { //判断模式功能码 呼吸灯
HAL_NVIC_DisableIRQ(DMA1_Channel4_IRQn); //关闭串口DMA通道,以便DMA发送WS2812数据
HAL_NVIC_DisableIRQ(DMA1_Channel5_IRQn); //关闭串口DMA通道,以便DMA发送WS2812数据
HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn); //开启WS2812用DMA通道,以便DMA发送WS2812数据
rgb_run_breathe(color_1, LED_NUM, LED_STEP_n);
HAL_NVIC_DisableIRQ(DMA1_Channel1_IRQn); //关闭WS2812DMA通道,以便DMA发送串口数据
HAL_NVIC_EnableIRQ(DMA1_Channel4_IRQn); //开启串口用DMA通道,以便DMA发送串口数据
HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn); //开启串口用DMA通道,以便DMA发送串口数据
}else {
break;
}
} else if (LED_DIRECT == 1) { //判断方向功能码反向
//判断模式功能码
if (LED_MOD == 0) { //判断模式功能码 全亮
HAL_NVIC_DisableIRQ(DMA1_Channel4_IRQn); //关闭串口DMA通道,以便DMA发送WS2812数据
HAL_NVIC_DisableIRQ(DMA1_Channel5_IRQn); //关闭串口DMA通道,以便DMA发送WS2812数据
HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn); //开启WS2812用DMA通道,以便DMA发送WS2812数据
RGB_COLOR(LED_NUM, color_1);
HAL_NVIC_DisableIRQ(DMA1_Channel1_IRQn); //关闭WS2812DMA通道,以便DMA发送串口数据
HAL_NVIC_EnableIRQ(DMA1_Channel4_IRQn); //开启串口用DMA通道,以便DMA发送串口数据
HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn); //开启串口用DMA通道,以便DMA发送串口数据
} else if (LED_MOD == 1) { //判断模式功能码 流水灯
HAL_NVIC_DisableIRQ(DMA1_Channel4_IRQn); //关闭串口DMA通道,以便DMA发送WS2812数据
HAL_NVIC_DisableIRQ(DMA1_Channel5_IRQn); //关闭串口DMA通道,以便DMA发送WS2812数据
HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn); //开启WS2812用DMA通道,以便DMA发送WS2812数据
rgb_strip_b(LED_NUM, LED_STEP_n, color_1);
HAL_NVIC_DisableIRQ(DMA1_Channel1_IRQn); //关闭WS2812DMA通道,以便DMA发送串口数据
HAL_NVIC_EnableIRQ(DMA1_Channel4_IRQn); //开启串口用DMA通道,以便DMA发送串口数据
HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn); //开启串口用DMA通道,以便DMA发送串口数据
} else if (LED_MOD == 2) { //判断模式功能码 跑马灯
HAL_NVIC_DisableIRQ(DMA1_Channel4_IRQn); //关闭串口DMA通道,以便DMA发送WS2812数据
HAL_NVIC_DisableIRQ(DMA1_Channel5_IRQn); //关闭串口DMA通道,以便DMA发送WS2812数据
HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn); //开启WS2812用DMA通道,以便DMA发送WS2812数据
rgb_run_b(LED_NUM, LED_STEP_n, color_1);
HAL_NVIC_DisableIRQ(DMA1_Channel1_IRQn); //关闭WS2812DMA通道,以便DMA发送串口数据
HAL_NVIC_EnableIRQ(DMA1_Channel4_IRQn); //开启串口用DMA通道,以便DMA发送串口数据
HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn); //开启串口用DMA通道,以便DMA发送串口数据
} else if (LED_MOD == 3) { //判断模式功能码 流水灯
HAL_NVIC_DisableIRQ(DMA1_Channel4_IRQn); //关闭串口DMA通道,以便DMA发送WS2812数据
HAL_NVIC_DisableIRQ(DMA1_Channel5_IRQn); //关闭串口DMA通道,以便DMA发送WS2812数据
HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn); //开启WS2812用DMA通道,以便DMA发送WS2812数据
rgb_strip_b_rsv(LED_NUM, LED_STEP_n, color_1);
HAL_NVIC_DisableIRQ(DMA1_Channel1_IRQn); //关闭WS2812DMA通道,以便DMA发送串口数据
HAL_NVIC_EnableIRQ(DMA1_Channel4_IRQn); //开启串口用DMA通道,以便DMA发送串口数据
HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn); //开启串口用DMA通道,以便DMA发送串口数据
} else if (LED_MOD == 4) { //判断模式功能码 跑马灯
HAL_NVIC_DisableIRQ(DMA1_Channel4_IRQn); //关闭串口DMA通道,以便DMA发送WS2812数据
HAL_NVIC_DisableIRQ(DMA1_Channel5_IRQn); //关闭串口DMA通道,以便DMA发送WS2812数据
HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn); //开启WS2812用DMA通道,以便DMA发送WS2812数据
rgb_run_b_rsv(LED_NUM, LED_STEP_n, color_1);
HAL_NVIC_DisableIRQ(DMA1_Channel1_IRQn); //关闭WS2812DMA通道,以便DMA发送串口数据
HAL_NVIC_EnableIRQ(DMA1_Channel4_IRQn); //开启串口用DMA通道,以便DMA发送串口数据
HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn); //开启串口用DMA通道,以便DMA发送串口数据
} else if (LED_MOD == 5) { //判断模式功能码 呼吸灯
HAL_NVIC_DisableIRQ(DMA1_Channel4_IRQn); //关闭串口DMA通道,以便DMA发送WS2812数据
HAL_NVIC_DisableIRQ(DMA1_Channel5_IRQn); //关闭串口DMA通道,以便DMA发送WS2812数据
HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn); //开启WS2812用DMA通道,以便DMA发送WS2812数据
rgb_run_b_trans_rsv(color_1, color_2, LED_NUM, LED_STEP_n, LEN_1, LEN_2);
HAL_NVIC_DisableIRQ(DMA1_Channel1_IRQn); //关闭WS2812DMA通道,以便DMA发送串口数据
HAL_NVIC_EnableIRQ(DMA1_Channel4_IRQn); //开启串口用DMA通道,以便DMA发送串口数据
HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn); //开启串口用DMA通道,以便DMA发送串口数据
} else if (LED_MOD == 6) { //判断模式功能码 呼吸灯
HAL_NVIC_DisableIRQ(DMA1_Channel4_IRQn); //关闭串口DMA通道,以便DMA发送WS2812数据
HAL_NVIC_DisableIRQ(DMA1_Channel5_IRQn); //关闭串口DMA通道,以便DMA发送WS2812数据
HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn); //开启WS2812用DMA通道,以便DMA发送WS2812数据
rgb_strip_trans_rsv(color_1, LED_NUM, LED_STEP_n);
HAL_NVIC_DisableIRQ(DMA1_Channel1_IRQn); //关闭WS2812DMA通道,以便DMA发送串口数据
HAL_NVIC_EnableIRQ(DMA1_Channel4_IRQn); //开启串口用DMA通道,以便DMA发送串口数据
HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn); //开启串口用DMA通道,以便DMA发送串口数据
} else if (LED_MOD == 7) { //判断模式功能码 呼吸灯
HAL_NVIC_DisableIRQ(DMA1_Channel4_IRQn); //关闭串口DMA通道,以便DMA发送WS2812数据
HAL_NVIC_DisableIRQ(DMA1_Channel5_IRQn); //关闭串口DMA通道,以便DMA发送WS2812数据
HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn); //开启WS2812用DMA通道,以便DMA发送WS2812数据
rgb_run_breathe_rsv(color_1, LED_NUM, LED_STEP_n);
HAL_NVIC_DisableIRQ(DMA1_Channel1_IRQn); //关闭WS2812DMA通道,以便DMA发送串口数据
HAL_NVIC_EnableIRQ(DMA1_Channel4_IRQn); //开启串口用DMA通道,以便DMA发送串口数据
HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn); //开启串口用DMA通道,以便DMA发送串口数据
}else {
break;
}
} else {
break;
}
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET); //系统监视灯
HAL_Delay(100);
HAL_IWDG_Refresh(&hiwdg);
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI|RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.LSIState = RCC_LSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
}
/* USER CODE BEGIN 4 */
/*************************************************************************************************************
功能:最后一行装载24个0,输出24个周期占空比为0的PWM波,作为最后reset延时,
这里总时长为24*1.2=30us > 24us(要求大于24us)
*************************************************************************************************************/
void Reset_Load(void)
{
uint8_t i;
for (i = 0; i < 24; i++) {
Pixel_Buf[LED_NUM][i] = 0;
}
}
/*************************************************************************************************************
功能:发送数组
参数:(&htim1)定时器1,
(TIM_CHANNEL_2)通道2,
((uint32_t *)Pixel_Buf)待发送数组,
(Pixel_NUM+1)*24)发送个数,数组行列相乘
*************************************************************************************************************/
void RGB_SendArray(void)
{
HAL_TIM_PWM_Start_DMA(&htim2, TIM_CHANNEL_3, (uint32_t *)Pixel_Buf, (LED_NUM + 1) * 24);
}
/*************************************************************************************************************
功能:数据全部清零
参数:Pixel_Len为显示LED个数
*************************************************************************************************************/
void RGB_RESET(uint16_t Pixel_Len)
{
uint16_t i;
for (i = 0; i < Pixel_Len; i++) { //给对应个数LED写入黑色
RGB_SetColor(i, color_list[0]);
}
}
/*************************************************************************************************************
功能:设定单个RGB LED的颜色,把结构体中RGB的24BIT转换为0码和1码
参数:LedId 为LED序号,
Color 为定义的颜色结构体
*************************************************************************************************************/
void RGB_SetColor(uint16_t LedId, color_map_TypeDef Color)
{
uint8_t i;
if (LedId > LED_NUM) {
return; //avoid overflow 防止写入ID大于LED总数
}
for (i = 0; i < 8; i++) {
Pixel_Buf[LedId][i] = ((Color.red & (1 << (7 - i))) ? (CODE_1) : CODE_0); //数组某一行0~7转化存放G
}
for (i = 8; i < 16; i++) {
Pixel_Buf[LedId][i] = ((Color.green & (1 << (15 - i))) ? (CODE_1) : CODE_0); //数组某一行8~15转化存放R
}
for (i = 16; i < 24; i++) {
Pixel_Buf[LedId][i] = ((Color.blue & (1 << (23 - i))) ? (CODE_1) : CODE_0); //数组某一行16~23转化存放B
}
}
/*************************************************************************************************************
功能:设定n个RGB LED的颜色,把结构体中RGB的24BIT转换为0码和1码
参数:LedId 为LED序号,
LedNumber 为需要显示的LED数量,
Color 定义的颜色结构体
*************************************************************************************************************/
void RGB_SetnColor(uint16_t LedStart, uint16_t LedNumber, color_map_TypeDef Color)
{
uint16_t i, j;
if (LedStart > LED_NUM) {
return; //avoid overflow 防止写入ID大于LED总数
}
if ((LedStart + LedNumber) > LED_NUM) {
LedNumber = LED_NUM - LedStart; //avoid overflow 防止写入ID大于LED总数
}
for (j = LedStart; j < LedStart + LedNumber; j++) {
for (i = 0; i < 8; i++) {
Pixel_Buf[j][i] = ((Color.red & (1 << (7 - i))) ? (CODE_1) : CODE_0); //数组某一行0~7转化存放G
}
for (i = 8; i < 16; i++) {
Pixel_Buf[j][i] = ((Color.green & (1 << (15 - i))) ? (CODE_1) : CODE_0); //数组某一行8~15转化存放R
}
for (i = 16; i < 24; i++) {
Pixel_Buf[j][i] = ((Color.blue & (1 << (23 - i))) ? (CODE_1) : CODE_0); //数组某一行16~23转化存放B
}
}
}
/*************************************************************************************************************
功能:显示指定颜色
参数:Pixel_Len为显示LED总个数
Color 为颜色RGB结构体
*************************************************************************************************************/
void RGB_COLOR(uint16_t Pixel_Len, color_map_TypeDef Color)
{
uint8_t i;
for (i = 0; i < Pixel_Len / 10 ; i++) {
RGB_SetnColor(0, Pixel_Len, Color);
Reset_Load();
RGB_SendArray();
HAL_Delay(delay_ms * 10);
}
}
/*************************************************************************************************************
功能:显示指定颜色正向跑马灯
参数:Pixel_Len为显示LED个数
Color 为颜色RGB结构体
Pixel_Num 为多少个灯亮
*************************************************************************************************************/
void rgb_run_f(uint16_t Pixel_Len, uint16_t Pixel_Num, color_map_TypeDef Color)
{
uint16_t i;
//前Pixel_Num个,从1个开始亮
for (i = 0; i < Pixel_Num; i++) {
RGB_RESET(Pixel_Len);
RGB_SetnColor(0, i, Color);
Reset_Load();
RGB_SendArray();
HAL_Delay(delay_ms);
}
//从第Pixel_Num个,整体亮并流动,最后逐个消逝
for (i = 1; i < Pixel_Len; i++) {
RGB_RESET(Pixel_Len);
RGB_SetnColor(i, Pixel_Num, Color);
Reset_Load();
RGB_SendArray();
HAL_Delay(delay_ms);
}
}
/*************************************************************************************************************
功能:显示指定颜色"反显"正向跑马灯
参数:Pixel_Len为显示LED个数
Color 为颜色RGB结构体
Pixel_Num 为多少个灯亮
*************************************************************************************************************/
void rgb_run_f_rsv(uint16_t Pixel_Len, uint16_t Pixel_Num, color_map_TypeDef Color)
{
uint16_t i;
//前Pixel_Num个,从1个开始亮
for (i = 0; i < Pixel_Num; i++) {
RGB_SetnColor(0, Pixel_Len, Color);
RGB_SetnColor(0, i, color_list[0]);
Reset_Load();
RGB_SendArray();
HAL_Delay(delay_ms);
}
//从第Pixel_Num个,整体亮并流动,最后逐个消逝
for (i = 1; i < Pixel_Len; i++) {
RGB_SetnColor(0, Pixel_Len, Color);
RGB_SetnColor(i, Pixel_Num, color_list[0]);
Reset_Load();
RGB_SendArray();
HAL_Delay(delay_ms);
}
}
/*************************************************************************************************************
功能:显示指定颜色正向流水灯
参数:Pixel_Len为显示LED个数
Color 为颜色RGB结构体
*************************************************************************************************************/
void rgb_strip_f(uint16_t Pixel_Len, uint16_t Step, color_map_TypeDef Color)
{
uint16_t i;
for (i = 0; i < Pixel_Len; i += Step) {
RGB_RESET(Pixel_Len);
RGB_SetnColor(0, i, Color);
Reset_Load();
RGB_SendArray();
HAL_Delay(delay_ms);
}
}
/*************************************************************************************************************
功能:显示指定颜色"反显"正向流水灯
参数:Pixel_Len为显示LED个数
Color 为颜色RGB结构体
*************************************************************************************************************/
void rgb_strip_f_rsv(uint16_t Pixel_Len, uint16_t Step, color_map_TypeDef Color)
{
uint16_t i;
for (i = 0; i < Pixel_Len; i += Step) {
RGB_SetnColor(0, Pixel_Len, Color);
RGB_SetnColor(0, i, color_list[0]);
Reset_Load();
RGB_SendArray();
HAL_Delay(delay_ms);
}
}
/*************************************************************************************************************
功能:显示指定颜色反向跑马灯
参数:Pixel_Len为显示LED个数
Color 为颜色RGB结构体
Pixel_Num 为多少个灯亮
*************************************************************************************************************/
void rgb_run_b(uint16_t Pixel_Len, uint16_t Pixel_Num, color_map_TypeDef Color)
{
uint16_t i, j, Pixel_Num1;
//前Pixel_Num个,从1个开始亮
for (i = 0; i < Pixel_Num; i++) {
RGB_RESET(Pixel_Len);
RGB_SetnColor(Pixel_Len - i, Pixel_Num, Color);
Reset_Load();
RGB_SendArray();
HAL_Delay(delay_ms);
}
//从第Pixel_Num个,整体亮并流动,最后逐个消逝
for (i = Pixel_Num; i < Pixel_Len + Pixel_Num; i++) {
RGB_RESET(Pixel_Len);
Pixel_Num1 = Pixel_Num;
j = i;
if (Pixel_Len < i) {
Pixel_Num1 = Pixel_Num - (i - Pixel_Len);
j = Pixel_Len;
}
RGB_SetnColor(Pixel_Len - j, Pixel_Num1, Color);
Reset_Load();
RGB_SendArray();
HAL_Delay(delay_ms);
}
}
/*************************************************************************************************************
功能:显示指定颜色"反显"反向跑马灯
参数:Pixel_Len为显示LED个数
Color 为颜色RGB结构体
Pixel_Num 为多少个灯亮
*************************************************************************************************************/
void rgb_run_b_rsv(uint16_t Pixel_Len, uint16_t Pixel_Num, color_map_TypeDef Color)
{
uint16_t i, j, Pixel_Num1;
//前Pixel_Num个,从1个开始亮
for (i = 0; i < Pixel_Num; i++) {
RGB_SetnColor(0, Pixel_Len, Color);
RGB_SetnColor(Pixel_Len - i, Pixel_Num, color_list[0]);
Reset_Load();
RGB_SendArray();
HAL_Delay(delay_ms);
}
//从第Pixel_Num个,整体亮并流动,最后逐个消逝
for (i = Pixel_Num; i < Pixel_Len + Pixel_Num; i++) {
RGB_SetnColor(0, Pixel_Len, Color);
Pixel_Num1 = Pixel_Num;
j = i;
if (Pixel_Len < i) {
Pixel_Num1 = Pixel_Num - (i - Pixel_Len);
j = Pixel_Len;
}
RGB_SetnColor(Pixel_Len - j, Pixel_Num1, color_list[0]);
Reset_Load();
RGB_SendArray();
HAL_Delay(delay_ms);
}
}
/*************************************************************************************************************
功能:显示指定颜色反向流水灯
参数:Pixel_Len为显示LED个数
Color 为颜色RGB结构体
*************************************************************************************************************/
void rgb_strip_b(uint16_t Pixel_Len, uint16_t Step, color_map_TypeDef Color)
{
uint16_t i;
for (i = 0; i < Pixel_Len; i += Step) {
RGB_RESET(Pixel_Len);
RGB_SetnColor(Pixel_Len - i, i, Color);
Reset_Load();
RGB_SendArray();
HAL_Delay(delay_ms);
}
}
/*************************************************************************************************************
功能:显示指定颜色"反显"反向流水灯
参数:Pixel_Len为显示LED个数
Color 为颜色RGB结构体
*************************************************************************************************************/
void rgb_strip_b_rsv(uint16_t Pixel_Len, uint16_t Step, color_map_TypeDef Color)
{
uint16_t i;
for (i = 0; i < Pixel_Len; i += Step) {
RGB_SetnColor(0, Pixel_Len, Color);
RGB_SetnColor(Pixel_Len - i, i, color_list[0]);
Reset_Load();
RGB_SendArray();
HAL_Delay(delay_ms);
}
}
/*************************************************************************************************************
功能:设定 分段 颜色 及 过渡段 正向流水
参数:color_1 第一段颜色
color_2 第三段颜色
len_color1 第一段长度
len_color2 第三段长度
len_in 中间段长度
*************************************************************************************************************/
void Set_Color_Trans(color_map_TypeDef color_1, color_map_TypeDef color_2, uint16_t len_color1, uint16_t len_in, uint16_t len_color2)
{
color_map_TypeDef color;
uint8_t red_;
uint8_t green_;
uint8_t blue_;
uint8_t red_step;
uint8_t green_step;
uint8_t blue_step;
color.red = color_1.red;
color.green = color_1.green;
color.blue = color_1.blue;
//计算红色步长
if (color_1.red > color_2.red) {
red_ = color_1.red - color_2.red;
} else {
red_ = color_2.red - color_1.red;
}
red_step = red_ / len_in + 1;
//计算绿色步长
if (color_1.green > color_2.green) {
green_ = color_1.green - color_2.green;
} else {
green_ = color_2.green - color_1.green;
}
green_step = green_ / len_in + 1;
//计算蓝色步长
if (color_1.blue > color_2.blue) {
blue_ = color_1.blue - color_2.blue;
} else {
blue_ = color_2.blue - color_1.blue;
}
blue_step = blue_ / len_in + 1;
//
RGB_RESET(len_color1 + len_in + len_color2);
//设定颜色 第一段
RGB_SetnColor(0, len_color1, color_1);
//设定颜色 第三段
RGB_SetnColor(len_color1 + len_in, len_color2, color_2);
//设定 过渡 颜色
for (int i = 0; i < len_in + 1; i++) {
//红色过渡
if (color_1.red > color_2.red) {
if (color.red <= color_2.red || color.red < red_step) {
color.red = color_2.red;
} else {
color.red = color.red - red_step;
}
} else {
if (color.red >= color_2.red || (255 - color.red) < red_step) {
color.red = color_2.red;
} else {
color.red = color.red + red_step;
}
}
//绿色过渡
if (color_1.green > color_2.green) {
if (color.green <= color_2.green || color.green < green_step) {
color.green = color_2.green;
} else {
color.green = color.green - green_step;
}
} else {
if (color.green >= color_2.green || (255 - color.green) < green_step) {
color.green = color_2.green;
} else {
color.green = color.green + green_step;
}
}
//蓝色过渡
if (color_1.blue > color_2.blue) {
if (color.blue <= color_2.blue || color.blue < blue_step) {
color.blue = color_2.blue;
} else {
color.blue = color.blue - blue_step;
}
} else {
if (color.blue >= color_2.blue || (255 - color.blue) < blue_step) {
color.blue = color_2.blue;
} else {
color.blue = color.blue + blue_step;
}
}
RGB_SetColor(len_color1 + i, color);
}
}
/*************************************************************************************************************
功能:设定 分段 颜色 及 过渡段 颜色 反向流水
参数:color_1 第一段颜色
color_2 第三段颜色
len_color1 第一段长度
len_color2 第三段长度
len_in 中间段长度
*************************************************************************************************************/
void rgb_run_f_trans_rsv(color_map_TypeDef color_1, color_map_TypeDef color_2, uint16_t Pixel_Len, uint16_t Step, uint16_t len_color1,
uint16_t len_color2)
{
for (int i = 0; i < Pixel_Len; i++) {
Set_Color_Trans(color_1, color_2, len_color1, Pixel_Len - len_color1 - len_color2, len_color2);
RGB_SetnColor(i, Step, color_list[0]);
Reset_Load();
RGB_SendArray();
HAL_Delay(delay_ms);
}
}
/*************************************************************************************************************
功能:设定 分段 颜色 及 过渡段 颜色 反向流水
参数:color_1 第一段颜色
color_2 第三段颜色
len_color1 第一段长度
len_color2 第三段长度
len_in 中间段长度
*************************************************************************************************************/
void rgb_run_b_trans_rsv(color_map_TypeDef color_1, color_map_TypeDef color_2, uint16_t Pixel_Len, uint16_t Step, uint16_t len_color1,
uint16_t len_color2)
{
for (int i = 0; i < Pixel_Len; i++) {
Set_Color_Trans(color_1, color_2, len_color1, Pixel_Len - len_color1 - len_color2, len_color2);
RGB_SetnColor(Pixel_Len - i, Step, color_list[0]);
Reset_Load();
RGB_SendArray();
HAL_Delay(delay_ms);
}
}
/*************************************************************************************************************
功能:设定一定长度同一颜色渐变流水灯
参数:color 颜色
Pixel_Len 长度
Step 步长
*************************************************************************************************************/
void rgb_strip_trans(color_map_TypeDef color, uint16_t Pixel_Len, uint16_t Step)
{
color_map_TypeDef color_t;
color_map_TypeDef color_t1;
color_map_TypeDef color_t2;
color_t.red = color.red;
color_t.green = color.green;
color_t.blue = color.blue;
for (int k = 0; k < Pixel_Len; k++) {
//写流动后空出的灯
if (k == 0) {
} else {
int l = k - 1;
for (int m = 0 ; m < (k / Step); m++) {
for (int n = 0; n < Step; n++) {
if (color_t.red == 0) {
} else {
color_t1.red = color_t.red - (color_t.red / Step) * n;
}
if (color_t.green == 0) {
} else {
color_t1.green = color_t.green - (color_t.green / Step) * n;
}
if (color_t.blue == 0) {
} else {
color_t1.blue = color_t.blue - (color_t.blue / Step) * n;
}
if (l < 0) {
break;
} else {
RGB_SetColor(l, color_t1);
}
l = l - 1;
}
}
}
//写前面流动的灯
for (int j = 0; j < (Pixel_Len / Step); j++) {
for (int i = 0; i < Step; i++) {
if (color_t.red == 0) {
} else {
color_t2.red = i*(color_t.red / Step);
}
if (color_t.green == 0) {
} else {
color_t2.green = i*(color_t.green / Step);
}
if (color_t.blue == 0) {
} else {
color_t2.blue = i*(color_t.blue / Step);
}
if (k + j *Step + i > Pixel_Len) {
} else {
RGB_SetColor(k + j *Step + i, color_t2);
}
}
}
Reset_Load();
RGB_SendArray();
HAL_Delay(delay_ms);
}
}
/*************************************************************************************************************
功能:设定一定长度同一颜色渐变反向流水灯
参数:color 颜色
Pixel_Len 长度
Step 步长
*************************************************************************************************************/
void rgb_strip_trans_rsv(color_map_TypeDef color, uint16_t Pixel_Len, uint16_t Step)
{
color_map_TypeDef color_t;
color_map_TypeDef color_t1;
color_map_TypeDef color_t2;
color_t.red = color.red;
color_t.green = color.green;
color_t.blue = color.blue;
for (int k = 0; k < Pixel_Len; k++) {
//写流动后空出的灯
if (k == 0) {
} else {
int l = Pixel_Len - k - 1;
for (int m = 0 ; m < ((Pixel_Len - k) / Step + 1); m++) {
for (int n = 0; n < Step; n++) {
if (color_t.red == 0) {
} else {
color_t1.red = (color_t.red / Step) * (Step - n);
}
if (color_t.green == 0) {
} else {
color_t1.green = (color_t.green / Step) * (Step - n);
}
if (color_t.blue == 0) {
} else {
color_t1.blue = (color_t.blue / Step) * (Step - n);
}
if (l < 0) {
break;
} else {
RGB_SetColor(l, color_t1);
}
l = l - 1;
}
}
}
//写前面流动的灯
for (int j = 0; j < (Pixel_Len / Step); j++) {
for (int i = 0; i < Step; i++) {
if (color_t.red == 0) {
} else {
color_t2.red = color_t.red - i*(color_t.red / Step);
}
if (color_t.green == 0) {
} else {
color_t2.green = color_t.green - i*(color_t.green / Step);
}
if (color_t.blue == 0) {
} else {
color_t2.blue = color_t.blue - i*(color_t.blue / Step);
}
if (Pixel_Len - k - 1 + j *Step + i > Pixel_Len) {
} else {
RGB_SetColor(Pixel_Len - k - 1 + j *Step + i, color_t2);
}
}
}
Reset_Load();
RGB_SendArray();
HAL_Delay(delay_ms);
}
}
/*************************************************************************************************************
功能:设定按颜色呼吸灯
参数:color颜色
Pixel_Len 长度
Step 呼吸步长
*************************************************************************************************************/
void rgb_run_breathe(color_map_TypeDef color, uint16_t Pixel_Len, uint16_t Step)
{
color_map_TypeDef color_t;
color_t.red = color.red;
color_t.green = color.green;
color_t.blue = color.blue;
for (int i = 0; i < Step; i++) {
color_t.red = color.red - i *color.red / Step;
color_t.green = color.green - i *color.green / Step;
color_t.blue = color.blue - i *color.blue / Step;
RGB_SetnColor(0, Pixel_Len, color_t);
Reset_Load();
RGB_SendArray();
HAL_Delay(1000 / Step);
}
for (int i = 0; i < Step+1; i++) {
color_t.red = i *color.red / Step;
color_t.green = i *color.green / Step;
color_t.blue = i *color.blue / Step;
RGB_SetnColor(0, Pixel_Len, color_t);
Reset_Load();
RGB_SendArray();
HAL_Delay(1000 / Step);
}
}
/*************************************************************************************************************
功能:设定按颜色呼吸灯
参数:color颜色
Pixel_Len 长度
Step 呼吸步长
*************************************************************************************************************/
void rgb_run_breathe_rsv(color_map_TypeDef color, uint16_t Pixel_Len, uint16_t Step)
{
color_map_TypeDef color_t;
color_t.red = color.red;
color_t.green = color.green;
color_t.blue = color.blue;
for (int i = 0; i < Step; i++) {
color_t.red = i *color.red / Step;
color_t.green = i *color.green / Step;
color_t.blue = i *color.blue / Step;
RGB_SetnColor(0, Pixel_Len, color_t);
Reset_Load();
RGB_SendArray();
HAL_Delay(1000 / Step);
}
for (int i = 0; i < Step; i++) {
color_t.red = color.red - i *color.red / Step;
color_t.green = color.green - i *color.green / Step;
color_t.blue = color.blue - i *color.blue / Step;
RGB_SetnColor(0, Pixel_Len, color_t);
Reset_Load();
RGB_SendArray();
HAL_Delay(1000 / Step);
}
}
/*************************************************************************************************************
功能:modbus初始化,根据GPIO PB3-PB10 设定地址
*************************************************************************************************************/
void Modbus_Init(void)
{
Modbus.address = 0x00; /* 基地址位00 */
uint16_t a1 = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_3);
uint16_t a2 = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_4);
uint16_t a3 = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_5);
uint16_t a4 = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_6);
uint16_t a5 = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_7);
uint16_t a6 = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_8);
uint16_t a7 = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_9);
uint16_t a8 = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_10);
Modbus.address = Modbus.address | (a1 << 0);
Modbus.address = Modbus.address | (a2 << 1);
Modbus.address = Modbus.address | (a3 << 2);
Modbus.address = Modbus.address | (a4 << 3);
Modbus.address = Modbus.address | (a5 << 4);
Modbus.address = Modbus.address | (a6 << 5);
Modbus.address = Modbus.address | (a7 << 6);
Modbus.address = Modbus.address | (a8 << 7);
printf("Modbus.address:%d \r\n", Modbus.address); // 显示Modbus地址
}
/*************************************************************************************************************
功能:mdbus命令处理主程序
*************************************************************************************************************/
void Modbus_processing(void)
{
uint16_t crc, rccrc; //定义两个获取接收和计算校验码的变量
crc = Modbus_CRC16(&Modbus.receive[0], xUSART1.receiveNUM - 2); //获取到接收的数据进行计算
rccrc = (Modbus.receive[xUSART1.receiveNUM - 2] << 8) + Modbus.receive[xUSART1.receiveNUM - 1]; //获取接收数组的校验位
if (crc == rccrc) { //校验码相同才可以进入
if (Modbus.receive[0] == Modbus.address) { //判断基地址
switch (Modbus.receive[1]) { //判断功能码
case 3:
Function_03();
break;
case 6:
Function_06();
break;
case 16:
Function_16();
break;
}
} else if (Modbus.receive[0] == 0) { //基地址不一样返回空
}
}
}
/*************************************************************************************************************
功能03:主机读取从机多寄存器
*************************************************************************************************************/
void Function_03(void)
{
uint16_t Regadd, Reglen, crc;
uint8_t i, j;
i = 0;
Regadd = (Modbus.receive[2] << 8) + Modbus.receive[3]; //要读取寄存器的首地址
Reglen = (Modbus.receive[4] << 8) + Modbus.receive[5]; //要读取寄存器个数
//开始打包数据包
Modbus.send[i++] = Modbus.address; //ID号
Modbus.send[i++] = 0x03; //功能码
Modbus.send[i++] = ((Reglen * 2) % 256); //返回字节个数
for (j = 0; j < Reglen; j++) {
Modbus.send[i++] = Reg[Regadd + j] >> 8; //寄存器数据的高位;因为寄存器是16位,所以要分成2个8位发送
Modbus.send[i++] = Reg[Regadd + j] % 256; //寄存器数据的地位
}
crc = Modbus_CRC16(Modbus.send, i); //计算校验码;同理校验码是16位
Modbus.send[i++] = crc >> 8; //返回校验码高位
Modbus.send[i++] = crc % 256; //返回校验码地位
//打包好数据开始发送
HAL_UART_Transmit_DMA(&huart1, (uint8_t *)Modbus.send, i); // 发送方式DMA
}
/*************************************************************************************************************
功能06:主机写入从机单寄存器
*************************************************************************************************************/
void Function_06(void)
{
uint16_t Regadd, crc, val; //地址;验证码;要修改的值;
uint16_t i;
i = 0;
Regadd = (Modbus.receive[2] << 8) + Modbus.receive[3]; //获取要修改的地址
val = (Modbus.receive[4] << 8) + Modbus.receive[5]; //获取修改的数值
Reg[Regadd] = val; //修改数值
//开始打包回应包
Modbus.send[i++] = Modbus.address; //从机地址
Modbus.send[i++] = 0x06; //功能码
Modbus.send[i++] = Regadd >> 8; //返回写入地址
Modbus.send[i++] = Regadd % 256;
Modbus.send[i++] = val >> 8; //返回写入数值
Modbus.send[i++] = val % 256;
crc = Modbus_CRC16(Modbus.send, i); //校验码
Modbus.send[i++] = crc >> 8; //返回校验码高位
Modbus.send[i++] = crc % 256; //返回校验码地位
flashWriteData(PARA_SIZE, Reg, 9);
//数据打包完开始发回
HAL_UART_Transmit_DMA(&huart1, (uint8_t *)Modbus.send, i); // 发送方式DMA
}
/*************************************************************************************************************
功能16:主机写入从机多寄存器
*************************************************************************************************************/
void Function_16(void)
{
uint16_t Regadd, crc, Regnum; //地址;验证码;要修改的值;
uint16_t i;
i = 0;
Regadd = (Modbus.receive[2] << 8) + Modbus.receive[3]; //获取要修改的地址
Regnum = (Modbus.receive[4] << 8) + Modbus.receive[5]; //获取要修改的数量
uint16_t k = 7; // 跳过 1地址+1功能码+2寄存器起始地址+2寄存器数量+1数据数量
for (uint16_t j = 0; j < Regnum; j++) {
Reg[Regadd + j] = (uint16_t)((Modbus.receive[k] << 8) | Modbus.receive[k + 1]);
k += 2;
}
//修改数值
//开始打包回应包
Modbus.send[i++] = Modbus.address; //从机地址
Modbus.send[i++] = 0x10; //功能码
Modbus.send[i++] = Regadd >> 8; //返回写入地址
Modbus.send[i++] = Regadd % 256;
for (uint16_t j = 0; j < Regnum; j++) { //返回写入数值
Modbus.send[i++] = Reg[Regadd + j] >> 8;
Modbus.send[i++] = Reg[Regadd + j] % 256;
}
flashWriteData(PARA_SIZE, Reg, 9);
crc = Modbus_CRC16(Modbus.send, i); //校验码
Modbus.send[i++] = crc >> 8; //返回校验码高位
Modbus.send[i++] = crc % 256; //返回校验码地位
//数据打包完开始发回
HAL_UART_Transmit_DMA(&huart1, (uint8_t *)Modbus.send, i); // 发送方式DMA
}
/*************************************************************************************************************
功能:modbus_CRC16处理程序
参数1:数组指针
参数2;长度
*************************************************************************************************************/
uint16_t Modbus_CRC16(uint8_t *buffer, uint16_t buffer_length)
{
uint16_t crc = 0xFFFF;
for (uint16_t i = 0; i < buffer_length; i++) {
crc ^= (uint16_t)buffer[i];
for (uint8_t j = 0; j < 8; j++) {
if (crc & 0x0001) {
crc = (crc >> 1) ^ 0xA001;
} else {
crc = crc >> 1;
}
}
}
crc = (crc >> 8) | (crc << 8);
return crc;
}
/*************************************************************************************************************
//paramSizeKb 程序大小,要写入FLASH的位置起始点
//data 准备写入数据
//len 大小
*************************************************************************************************************/
bool flashWriteData(int paramSizeKb, uint16_t data[], size_t len)
{
HAL_FLASH_Unlock();//解锁flash
//准备擦除整页,写入前需要擦除
FLASH_EraseInitTypeDef f;
f.TypeErase = FLASH_TYPEERASE_PAGES;//页擦除
f.PageAddress = PAGE_START_ADDRESS + (1024 * paramSizeKb);//擦除页地址
f.NbPages = 1;//擦除1页
uint32_t PageError = 0;
HAL_FLASHEx_Erase(&f, &PageError);//擦除PageError == 0xFFFFFFFF表示成功
if (PageError != 0xFFFFFFFF) {
return false;
}
//开始写数据
uint32_t startAddressIndex = PAGE_START_ADDRESS + (1024 * paramSizeKb);
//startAddressIndex += 2,写入位置,每次+2是因为存储的类型是uint16_t,占用16bit,2字节
for (int i = 0 ; i < len; i ++, startAddressIndex += 2) {
//写入数据
HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, startAddressIndex, data[i]); //uint16_t 用 HALFWORD,uint32_t 用 WORD
}
//重新上锁
HAL_FLASH_Lock();
return true;
}
/*************************************************************************************************************
//读取数据
//paramSizeKb 程序大小,要读取FLASH的位置起始点
//data 读入数据
//len 读入数据长度
*************************************************************************************************************/
void flashReadData(int paramSizeKb, uint16_t *data, size_t len)
{
uint32_t startAddressIndex = PAGE_START_ADDRESS + (1024 * paramSizeKb);
for (int i = 0; i < len; i++, startAddressIndex += 2) {
data[i] = *(__IO uint32_t *)(startAddressIndex);
}
}
/*************************************************************************************************************
功能:求两数的最大值
*************************************************************************************************************/
uint8_t max(uint8_t a, uint8_t b)
{
if (a > b) {
return a;
} else {
return b;
}
}
/*************************************************************************************************************
功能:求两数的最小值
*************************************************************************************************************/
uint8_t min(uint8_t a, uint8_t b)
{
if (a < b) {
return a;
} else {
return b;
}
}
/*************************************************************************************************************
功能:usart接收中断处理函数
*************************************************************************************************************/
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
if (huart == &huart1) { // 判断串口
__HAL_UNLOCK(huart); // 解锁串口状态
xUSART1.receiveNUM = Size; // 把接收字节数,存入结构体xUSART1.ReceiveNum
memset(Modbus.receive, 0, sizeof(Modbus.receive)); // 清除Modbus.receive前一帧接收到的数据
memset(xUSART1.receiveData, 0, sizeof(xUSART1.receiveData)); // 清除xUSART1.ReceiveData前一帧接收到的数据
memcpy(xUSART1.receiveData, xUSART1.BuffTemp, Size); // 把新数据,从临时缓存中,复制到xUSART1.ReceiveData[]
memcpy(Modbus.receive, xUSART1.BuffTemp, Size); // 把新数据,从临时缓存中,复制到Modbus.receive
//HAL_UARTEx_ReceiveToIdle_DMA(&huart1, xUSART1.BuffTemp,
// sizeof(xUSART1.BuffTemp)); // 再次开启DMA空闲中断;不要放在这里,会出现开启不了的可能,应放到中断处理函数里
}
}
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
while (1) {
}
/* USER CODE END Error_Handler_Debug */
}
#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 CODE BEGIN 6 */
/* 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) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */