110VCGQ/project/110VCGQV5.6/user/Src/user.c
2024-12-30 15:29:57 +08:00

880 lines
19 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* user.c
*
* Created on: 2023年6月25日
* Author: wyf
*/
#include "user.h"
volatile uint8_t usart_count = 0; //串口接收数据个数
uint8_t RxBuff[BUFF_LEN] = {0}; //串口接收缓冲区
uint8_t TXBuff[BUFF_LEN] = {0}; //串口发送缓冲区
uint8_t uBuff[BUFF_LEN] = {0}; //用户缓冲区
volatile int8_t polarity = 1,adc_state = 1; //电场极性,投退状态
volatile uint8_t electric_flag = 0; //外加的反向电场极限0为负1为正
volatile uint8_t motor_state = 1; //电机状态,0为正常, 1不正常
volatile uint16_t RS485ADDR = 0; //485地址
uint16_t RegularConvData_Tab[ADCBUFF_LEN] = {0};//ADC采集原始数据
volatile int16_t adc_max = 0; //最终峰峰值
volatile int16_t adc_positive = 0, adc_negative=0; //加外加电场后的adc值
volatile int16_t estimate_value = 40; //投退判断的差值
volatile uint16_t pwm_pulse = 0; //pwm波脉宽
volatile int16_t adcValue_factor = 0; //adc测量值的修正系数*10
volatile int16_t adcValue_addnum = 0; //adc测量值的加减系数
volatile uint16_t motor_runtime =0; //电机运行时间
volatile uint16_t bad_runtime = 0; //恶劣环境运行时间
volatile int16_t baud_rate = 0; //波特率0:9600, 1:19200 2:57600 3: 115200
uint8_t tempe = 0,humidness = 0; //温度湿度
//uint32_t current_addr = FLASHmotor_runtime; //记录当前电机运行时间的地址
int16_t threshold_value = 300; //传感器上限阈值低于300时认为是退
int16_t voltage = 0; //电压
int16_t reference =0; //电压参考值
int16_t voltage_thresh = 60; //投退电压阈值
char version_string[]="DCE-2406-V5.6_HAL";
uint16_t version_number = 560;
int16_t hard_version = 510;
uint16_t user_temp = 0;
/*1:传感器数据 2:投退状态 3电机状态
* 4PWM波占空比 5传感器缩放系数 6传感器加减系数
* 7电机运行时间 8:设置波特率 9温湿度
* 10:方波投退判断阈值 11传感器退阈值 12:电压值
* 13:电压阈值,电压小于该值时为退
*/
int16_t user_register[14] = {0}; //寄存器值
void user_init(void)
{
__HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE);
__HAL_UART_CLEAR_IT(&huart1,UART_CLEAR_IDLEF|UART_CLEAR_TCF);
bsp_InitTimer();
AHT20_Init(&SENx,2000,0x38); //2000:读取数据周期2S; 0x38:AHT20地址
motor_state =1;
}
//求adc波形的峰峰值
void ADC_MAX(void)
{
uint8_t i =0;
static uint8_t number = 0;
uint16_t max = 0,min = 0;
static int16_t adc1_max = 0;
max = RegularConvData_Tab[0];
min = RegularConvData_Tab[0];
for(i = 1;i<ADCBUFF_LEN;i++)
{
if(RegularConvData_Tab[i] > max )
{
max = RegularConvData_Tab[i];
}
else if(RegularConvData_Tab[i] < min )
{
min = RegularConvData_Tab[i];
}
}
if(max - min > 0)
{
adc1_max += max - min;
}
if(number++>=4)
{
adc1_max = adc1_max/5*3300/4095;
adc1_max = adc1_max*adcValue_factor/10 + adcValue_addnum;
adc1_max = polarity*adc1_max;
adc_max = adc1_max;
if(electric_flag == 1)
{
if(adc_max>adc_positive)
{
adc_positive = adc_max;
}
}
else if(electric_flag == 0)
{
if(adc_max<adc_negative)
{
adc_negative = adc_max;
}
}
adc1_max = 0;
number = 0;
}
}
//处理请求
void Usart_Receive(void)
{
if( (uint16_t)uBuff[0] == RS485ADDR && usart_count == 8)
{
switch(uBuff[1])
{
case 0x03: //读传感器数据
MODBUS_03H();
break;
case 0x06:
MODBUS_06H();
break;
default:break;
}
}
else if((uint16_t)uBuff[0] == 0 && usart_count== 8)
{
switch(uBuff[1])
{
case 0x06:
MODBUS_06H();
break;
default:break;
}
}
}
/************************************************************
* Name: CRC-16/MODBUS x16+x15+x2+1
* Poly: 0x8005
* Init: 0xFFFF
* Refin: True
* Refout: True
* Xorout: 0x0000
* Note:
**********************************************************/
uint16_t crc16_modbus(uint8_t *data, uint16_t length)
{
uint8_t i;
uint16_t crc = 0xffff; // Initial value
while(length--)
{
crc ^= *data++; // crc ^= *data; data++;
for (i = 0; i < 8; ++i)
{
if (crc & 1)
crc = (crc >> 1) ^ 0xA001; // 0xA001 = reverse 0x8005
else
crc = (crc >> 1);
}
}
return crc;
}
//03指令读取传感器数据
void MODBUS_03H(void)
{
//接收到的数据帧
//485地址 功能位 寄存器地址 寄存器个数 crc低位 crc高位
uint8_t crch,crcl;
uint16_t crcack;
uint16_t addr = (uint16_t)uBuff[2]<<8 | uBuff[3]; //寄存器地址
uint16_t number = (uint16_t)uBuff[4]<<8 | uBuff[5]; //寄存器数量
uint16_t crc = crc16_modbus(uBuff,6); //计算CRC
crch = crc>>8;
crcl = crc&0x00FF;
user_register[1] = adc_max;
user_register[2] = adc_state;
if(voltage == 0) user_register[2]= 0;
else if(abs(voltage) < voltage_thresh && user_temp>6)
{
user_register[2]= 0;
voltage = 0;
}
user_register[3] = motor_state;
user_register[4] = pwm_pulse;
user_register[5] = adcValue_factor;
user_register[6] = adcValue_addnum;
user_register[7] = motor_runtime;
user_register[8] = baud_rate;
user_register[9] = (humidness<<8)|tempe;
user_register[10] = estimate_value;
user_register[11] = threshold_value;
user_register[12] = voltage;
if(abs(adc_max)>3100)
{
user_register[12] =adc_max/abs(adc_max)*200;;
}
user_register[13] = voltage_thresh;
if( (addr+number) <= 14 && crcl == uBuff[6] && crch == uBuff[7])
{
uint8_t cnt = 0;
TXBuff[cnt++] = uBuff[0];
TXBuff[cnt++] = uBuff[1];
TXBuff[cnt++] = number*2; //数据个数,单位/字节
for(uint8_t i =0;i<number;i++)
{
TXBuff[cnt++] = user_register[addr+i] >>8;
TXBuff[cnt++] = user_register[addr+i] & 0xFF;
}
crcack = crc16_modbus(TXBuff,cnt);
TXBuff[cnt++] = crcack & 0xff;
TXBuff[cnt++] = crcack >>8;
send_ack(cnt);
}
//读取版本号
if(addr == 0x00FF && number == 0x0001 && crcl== uBuff[6] && crch== uBuff[7]) //比较寄存器值和CRC校验值
{
uint8_t i;
for(i=0;i<strlen(version_string);i++)
{
TXBuff[i] = version_string[i];
}
send_ack(strlen(version_string)); //打印版本号
}
//版本号,软件版本
if( addr == 0xFD && crcl == uBuff[6] && crch == uBuff[7])
{
uint8_t cnt = 0;
TXBuff[cnt++] = uBuff[0];
TXBuff[cnt++] = uBuff[1];
TXBuff[cnt++] = number*2; //数据个数,单位/字节
TXBuff[cnt++] = version_number >>8;
TXBuff[cnt++] = version_number & 0xFF;
crcack = crc16_modbus(TXBuff,cnt);
TXBuff[cnt++] = crcack & 0xff;
TXBuff[cnt++] = crcack >>8;
send_ack(cnt);
}
//版本号,硬件版本
if( addr == 0xFC && crcl == uBuff[6] && crch == uBuff[7])
{
uint8_t cnt = 0;
TXBuff[cnt++] = uBuff[0];
TXBuff[cnt++] = uBuff[1];
TXBuff[cnt++] = number*2; //数据个数,单位/字节
TXBuff[cnt++] = hard_version >>8;
TXBuff[cnt++] = hard_version & 0xFF;
crcack = crc16_modbus(TXBuff,cnt);
TXBuff[cnt++] = crcack & 0xff;
TXBuff[cnt++] = crcack >>8;
send_ack(cnt);
}
}
uint8_t reference_flag =0;
//06指令设置寄存器
void MODBUS_06H(void)
{
int16_t data = ((int16_t)uBuff[4]<<8)|uBuff[5]; //要修改的数据
uint16_t reg = ((int16_t)uBuff[2]<<8)|uBuff[3]; //寄存器地址
uint16_t crc = crc16_modbus( uBuff,6); //计算CRC
for(uint8_t i = 0; i<6; i++)
{
TXBuff[i] = uBuff[i];
}
TXBuff[6] = crc&0xff;
TXBuff[7] = crc>>8;
//修改地址
if(reg == 0x000f && TXBuff[6]== uBuff[6] && TXBuff[7]== uBuff[7])
{
if(data>=1 && data <= 247)
{
uint8_t temp = RS485ADDR;
RS485ADDR = data;
if(write_flash() == 0)
{
if(uBuff[1] != 0)
{
send_ack(8);
}
}
else
{
RS485ADDR = temp;
}
}
else {
TXBuff[4] = 0xFF;
TXBuff[5] = 0xFF;
crc = crc16_modbus( uBuff,6); //计算CRC
TXBuff[6] = crc&0xff;
TXBuff[7] = crc>>8;
if(uBuff[0] != 0) //广播地址不返回
{
send_ack(8);
}
}
}
//设置PWM波占空比
else if(reg == 0x0004 && TXBuff[6]== uBuff[6] && TXBuff[7]== uBuff[7])
{
if(data>=0 && data<= 1000) //从机地址要大于等于1小于等于247
{
int16_t temp = pwm_pulse;
pwm_pulse = data; //更新地址
if(write_flash() == 0)
{
send_ack(8);
__HAL_TIM_SET_COMPARE(&htim14,TIM_CHANNEL_1,pwm_pulse); //设置脉宽
}
else
{
pwm_pulse = temp;
}
}
}
//设置传感器缩放系数
else if(reg == 0x0005 && TXBuff[6]== uBuff[6] && TXBuff[7]== uBuff[7])
{
if(data>=-3300 && data<= 3300) //数据大于1小于3300
{
int16_t temp = adcValue_factor;
adcValue_factor = data*10/adc_max;
if(data >= 5 && data <= 20)adcValue_factor = data;
if(adcValue_factor>=5 && adcValue_factor<=20)
{
if(write_flash() == 0)
{
send_ack(8);
}
else
{
adcValue_factor = temp;
}
}
}
}
//设置传感器加减系数
else if(reg == 0x0006 && TXBuff[6]== uBuff[6] && TXBuff[7]== uBuff[7])
{
if(data >= -3300 && data <= 3300 && data != 0)
{
int16_t temp = adcValue_addnum;
adcValue_addnum = data;
if(write_flash() == 0)
{
send_ack(8);
}
else
{
adcValue_addnum = temp;
}
}
if(data ==0)
{
send_ack(8);
DISABLE_INT();
NVIC_SystemReset();
}
}
/*
//设置电机运行时间
else if(reg == 0x0007 && TXBuff[6]== uBuff[6] && TXBuff[7]== uBuff[7])
{
uint16_t temp = motor_runtime;
motor_runtime = data;
current_addr = 0x080077D8; //在开头的位置写,则会清除整个区域
bad_runtime =0;
if(write_runtime() == 0)
{
send_ack(8);
}
else
{
motor_runtime =temp ;
}
}
*/
//设置波特率
else if(reg == 0x0008 && TXBuff[6]== uBuff[6] && TXBuff[7]== uBuff[7])
{
if(data >= 0 && data <= 3 )
{
int16_t temp = baud_rate;
baud_rate = data;
if(write_flash() == 0)
{
send_ack(8);
Uart_SetBaud(baud_rate);
}
else
{
baud_rate = temp;
}
}
}
//设置投退方波阈值
else if(reg == 0x000A && TXBuff[6]== uBuff[6] && TXBuff[7]== uBuff[7])
{
if(data >= 0 && data <= 1500 )
{
int16_t temp = estimate_value;
estimate_value = data;
if(write_flash() == 0)
{
send_ack(8);
}
else
{
estimate_value = temp;
}
}
}
//设置退阈值
else if(reg == 0x000B && TXBuff[6]== uBuff[6] && TXBuff[7]== uBuff[7])
{
if(data >= 0 && data <= 1500 )
{
int16_t temp = threshold_value;
threshold_value = data;
if(write_flash() == 0)
{
send_ack(8);
}
else
{
threshold_value = temp;
}
}
}
//设置电压参考值
else if(reg == 12 && TXBuff[6]== uBuff[6] && TXBuff[7]== uBuff[7])
{
if(data >= -220 && data <= 220 )
{
int16_t temp = reference;
if(data != 0)
{
reference = 110.0/data*adc_max;
}
else {
reference =1;
}
reference_flag = 1;
if(write_flash() == 0)
{
send_ack(8);
}
else
{
reference = temp;
}
}
}
//设置电压阈值
else if(reg == 13 && TXBuff[6]== uBuff[6] && TXBuff[7]== uBuff[7])
{
if(data >= 0 && data <= 220 )
{
int16_t temp = voltage_thresh;
voltage_thresh = data;
if(write_flash() == 0)
{
send_ack(8);
}
else
{
voltage_thresh = temp;
}
}
}
}
uint8_t writeflash(void)
{
FLASH_EraseInitTypeDef EraseInitType;
uint32_t PageError;
uint8_t a[24] = {0};
int16_t reference_temp;
//电压标定值
reference_temp = *(int16_t*)(FLASH485_ADDR+14);
if(reference_temp == 0x0000 ||reference_temp == -1)
{
reference_temp = 0;
}
//stm32g030F4P6: flash 32k,2k一页共16页
EraseInitType.TypeErase = FLASH_TYPEERASE_PAGES; //页擦页
EraseInitType.Banks =FLASH_BANK_1;
EraseInitType.Page = 15; //擦除页地址
EraseInitType.NbPages = 1; //擦除数量
//stm32是小端模式低位在前
a[0] = RS485ADDR&0xFF; //地址
a[1] = RS485ADDR>>8;
a[2] = pwm_pulse&0xFF; //占空比
a[3] = pwm_pulse>>8;
a[4] = adcValue_factor&0xFF; //数据修正的比例系数
a[5] = adcValue_factor>>8;
a[6] = adcValue_addnum & 0xFF; //加减系数
a[7] = adcValue_addnum >>8;
a[8] = baud_rate & 0xFF; //加减系数
a[9] = baud_rate >>8;
a[10] = estimate_value & 0xFF;
a[11] = estimate_value >>8;
a[12] = threshold_value & 0xFF;
a[13] = threshold_value >>8;
a[14] = reference_temp & 0xFF;
a[15] = reference_temp >> 8;
if(reference_flag == 1)
{
a[14] = reference & 0xFF;
a[15] = reference >> 8;
reference_flag = 0;
}
a[16] = voltage_thresh & 0xFF;
a[17] = voltage_thresh >> 8;
HAL_FLASH_Unlock(); //解锁
if(HAL_FLASHEx_Erase(&EraseInitType, &PageError) != HAL_OK) //擦除
{
HAL_FLASH_Lock();
return 1;
}
uint64_t *b = (uint64_t*)a;
// uint8_t i = 0;
// for(i=0;i++;i<3)
// {
// if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, FLASH485_ADDR+i*8, *(b+i)) != HAL_OK)
// {
// HAL_FLASH_Lock();
// return 3 ;
// }
// }
if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, FLASH485_ADDR, *b) != HAL_OK)
{
HAL_FLASH_Lock();
return 3 ;
}
if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, FLASH485_ADDR+8, *(b+1) ) != HAL_OK)
{
HAL_FLASH_Lock();
return 3 ;
}
if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, FLASH485_ADDR+16, *(b+2) ) != HAL_OK)
{
HAL_FLASH_Lock();
return 3 ;
}
HAL_FLASH_Lock();
return 0;
}
//把参数写到flash中
uint8_t write_flash(void)
{
uint8_t a =0;
DISABLE_INT();
a= writeflash();
ENABLE_INT();
return a;
}
//取消运行时间功能
/*
uint8_t write_runtime(void)
{
FLASH_EraseInitTypeDef EraseInitType;
uint32_t PageError;
//stm32g030F4P6: flash 32k,2k一页共16页
EraseInitType.TypeErase = FLASH_TYPEERASE_PAGES; //页擦页
EraseInitType.Banks =FLASH_BANK_1;
EraseInitType.Page = 14; //擦除页地址
EraseInitType.NbPages = 1; //擦除数量
current_addr += 8;
HAL_FLASH_Unlock();
if(current_addr > 0x080077D8)
{
current_addr = FLASHmotor_runtime; //解锁
if(HAL_FLASHEx_Erase(&EraseInitType, &PageError) != HAL_OK) //擦除
{
HAL_FLASH_Lock();
return 1;
}
}
uint64_t b = motor_runtime; //<<16 | bad_runtime;
if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, current_addr, b) != HAL_OK)
{
HAL_FLASH_Lock();
return 3 ;
}
HAL_FLASH_Lock();
return 0;
}
*/
//发送数据参数数据长度数据放在全局变量txbuff中
void send_ack(uint8_t a)
{
HAL_GPIO_WritePin(TX485_EN_GPIO_Port, TX485_EN_Pin, GPIO_PIN_SET);//使能485芯片发送
HAL_UART_Transmit_DMA(&huart1, TXBuff, a);
while(HAL_DMA_GetState(&hdma_usart1_tx) != HAL_DMA_STATE_READY);
delay_ms(5);
HAL_GPIO_WritePin(TX485_EN_GPIO_Port, TX485_EN_Pin, GPIO_PIN_RESET);//使能485芯片接收
}
//外部中断回调函数,
void HAL_GPIO_EXTI_Rising_Callback(uint16_t GPIO_Pin)
{
static uint8_t count = 0,polaNumber =0;
static int16_t last_negative = 0;
static GPIO_PinState PH2_value =GPIO_PIN_RESET,PH1_value = GPIO_PIN_RESET;
PH2_value = HAL_GPIO_ReadPin(PH2_GPIO_Port, PH2_Pin);
PH1_value = HAL_GPIO_ReadPin(PH1_GPIO_Port, PH1_Pin);
if(GPIO_Pin == PH1_Pin && PH1_value == GPIO_PIN_SET )
{
//判断电机运动状态
static uint32_t last_tick = 0;
// last_tick = HAL_GetTick();
uint32_t a = HAL_GetTick();
if( (a -last_tick) < 8)
{
bsp_StartAutoTimer(4,1000); //1秒没有检测到上升沿说明电机不正常或红外线发射接收不正常
if(motor_state == 1)
{
bsp_StartAutoTimer(2,500); //led2闪烁
motor_state = 0;
}
}
last_tick = a;
//判断极性
if(PH2_value==GPIO_PIN_SET)
{
polaNumber ++;
}
count++;
if(count>=10)
{
if(polaNumber>=3)polarity=1;
else
{polarity = -1;}
count =0;
polaNumber =0;
}
}
else if(GPIO_Pin == SDA_Pin) //判断压板投退状态
{
bsp_StartAutoTimer(3,5000); //5秒没有上升下降沿说明可能没有加反向电场
static uint8_t posinumber =0,neganumber = 0,last_state=1;
if(HAL_GPIO_ReadPin(SDA_GPIO_Port, SDA_Pin) == GPIO_PIN_SET) //上升沿
{
electric_flag = 1;
motor_runtime = adc_positive - adc_negative;
if(adc_positive - adc_negative >estimate_value
&& adc_positive - last_negative >estimate_value)
{
posinumber++;
neganumber = 0;
if(posinumber>=3)
{
adc_state = 0; //0是退
}
if(posinumber>250)posinumber = 3;
}
else
{
neganumber++;
posinumber = 0;
if(neganumber>=2)
{
adc_state = 1; //1是投
if(last_state == 0)
{
reference =0;
}
}
if(neganumber>250)neganumber = 3;
}
last_negative =adc_negative;
static uint16_t thresh_cnt =0;
if( abs(adc_positive)<threshold_value && abs(adc_negative)<threshold_value)
{
thresh_cnt++;
if(thresh_cnt>=3)
{
adc_state = 0; //0是退
thresh_cnt =3;
}
}
else {
thresh_cnt = 0;
}
adc_positive = adc_max; //上升沿赋值正值,下降沿赋值负值
last_state = adc_state;
}
}
__HAL_GPIO_EXTI_CLEAR_RISING_IT(GPIO_Pin);
}
void HAL_GPIO_EXTI_Falling_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin == SDA_Pin)
{
if(HAL_GPIO_ReadPin(SDA_GPIO_Port, SDA_Pin) == GPIO_PIN_RESET)
{
electric_flag = 0;
}
adc_negative = adc_max;
}
}
void Uart_SetBaud(int16_t baud)
{
HAL_UART_DeInit(&huart1); //如果不清除DMA会产生bug
huart1.Instance = USART1;
huart1.Init.BaudRate = 9600;
if(baud == 1)
{
huart1.Init.BaudRate = 19200;
}
else if(baud == 2)
{
huart1.Init.BaudRate = 57600;
}
else if(baud == 3)
{
huart1.Init.BaudRate = 115200;
}
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
huart1.Init.ClockPrescaler = UART_PRESCALER_DIV1;
huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_UART_Init(&huart1) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_SetTxFifoThreshold(&huart1, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_SetRxFifoThreshold(&huart1, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_DisableFifoMode(&huart1) != HAL_OK)
{
Error_Handler();
}
__HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE);
__HAL_UART_CLEAR_IT(&huart1,UART_CLEAR_IDLEF|UART_CLEAR_TCF);
}
//计算电压值每6秒钟调用一次
void calculate_voltage(void)
{
static uint16_t last_count = 0,count =0;
static int16_t last_adc = 0;
static int8_t a = 0;
if(adc_state == 0)
{
voltage = 0;
}
else
{
if(reference == 0) //0为默认处理方式
{
count++;
a = adc_max/abs(adc_max);
voltage =a*110;
if(count -last_count >= 5 ) //每6秒钟调用一次
{
if(abs(adc_max-last_adc) < 40 && count >= 30)
{
reference = adc_max;
count =0;
}
last_count = count;
last_adc = adc_max;
}
}
else if(reference == 1) //人为设置电压参考值为0时的处理
{
voltage =0;
if(abs(adc_max-last_adc)>300 )
{
reference = 0;
write_flash();
}
last_adc = adc_max;
}
}
}