This commit is contained in:
2026-02-24 09:58:06 +08:00
parent fb4e311fbe
commit 9d69b29eed
161 changed files with 20379 additions and 7340 deletions
+192
View File
@@ -0,0 +1,192 @@
#include "algo_queue.h"
/* 计算队列中第i个元素的地址 */
#define at(i) (((char *)(queue->base))+(i)*(queue->dsize))
/* 数据赋值:将源地址s的数据复制到目标地址d */
#define assign(d, s) memcpy((d), (s), queue->dsize)
/* 获取队列中逻辑位置i的元素地址(考虑循环队列) */
#define qa(i) at((queue->head + queue->capacity + (i)) % (queue->capacity))
/* 简易内存复制函数 */
static void* memcpy(void* dest, const void* src, int n)
{
char* dst = dest;
const char* s = src;
while (n--) *dst++ = *s++;
return dest;
}
/* 将队列中从index开始的size个元素向前移动一位 */
static void move_forward(queue queue, int index, int size)
{
for (int i = index; i < index + size; i++) assign(qa(i - 1), qa(i));
}
/* 将队列中从index开始的size个元素向后移动一位 */
static void move_backward(queue queue, int index, int size)
{
for (int i = index + size; i > index; i--) assign(qa(i), qa(i - 1));
}
/**
* \brief 标准入队操作(队尾添加)
* \param[in] queue: 队列对象指针
* \param[in] data: 待添加数据地址(NULL表示仅移动指针)
* \return 1=成功, 0=失败(队列无效或已满)
*
* \details 在队列尾部添加新元素。如果队列已满则操作失败。
* 当data不为NULL时,将数据复制到队列存储区。
* 更新尾指针和队列大小。
*/
int queue_push(queue queue, void* data)
{
if (!queue) return 0; // 检查队列指针有效性
if (queue->size == queue->capacity) return 0; // 队列已满
if (data) assign(at(queue->tail), data); // 数据复制到队尾
queue->tail = (queue->tail + 1) % queue->capacity; // 更新尾指针(循环)
queue->size++; // 更新元素数量
return 1;
}
/**
* \brief 强制入队操作(覆盖式添加)
* \param[in] queue: 队列对象指针
* \param[in] data: 待添加数据地址(NULL表示仅移动指针)
* \return 1=成功, 0=失败(仅当队列无效时)
*
* \details 当队列未满时等同于queue_push()。
* 当队列已满时覆盖最旧数据(队头数据),
* 实现循环缓冲效果。
*/
int queue_push2(queue queue, void* data)
{
if (!queue) return 0;
if (queue->size < queue->capacity) return queue_push(queue, data); // 队列未满时调用标准入队
// 队列已满时覆盖队头数据(实现循环覆盖)
if (data) assign(at(queue->tail), data);
queue->tail = (queue->tail + 1) % queue->capacity;
queue->head = (queue->head + 1) % queue->capacity; // 头指针后移(覆盖最旧数据)
return 1;
}
/**
* \brief 出队操作(队头移除)
* \param[in] queue: 队列对象指针
* \param[out] data: 数据接收地址(NULL表示丢弃数据)
* \return 1=成功, 0=失败(队列无效或为空)
*
* \details 从队列头部移除元素。如果data不为NULL,
* 将移除的元素复制到指定地址。
* 更新头指针和队列大小。
*/
int queue_pop(queue queue, void* data)
{
if (!queue) return 0;
if (queue->size == 0) return 0; // 队列为空
if (data) assign(data, at(queue->head)); // 复制队头数据到输出
queue->head = (queue->head + 1) % queue->capacity; // 更新头指针(循环)
queue->size--; // 更新元素数量
return 1;
}
/**
* \brief 指定位置插入元素
* \param[in] queue: 队列对象指针
* \param[in] index: 插入位置索引(0=队头, size=队尾)
* \param[in] data: 待插入数据地址(NULL表示仅空出位置)
* \return 1=成功, 0=失败(索引越界或队列已满)
*
* \details 在指定位置插入新元素,后续元素后移。
* 自动选择最优移动方向(前移或后移元素)。
* 时间复杂度O(min(index, size-index))。
*/
int queue_insert(queue queue, int index, void* data)
{
if (!queue) return 0;
if (index < 0 || index > queue->size) return 0; // 索引越界检查
if (queue->size == queue->capacity) return 0; // 队列已满
// 根据插入位置选择最优移动方向
if (index <= queue->size / 2) {
// 向前移动前半部分元素
move_forward(queue, 0, index);
queue->head = (queue->head + queue->capacity - 1) % queue->capacity; // 头指针前移
} else {
// 向后移动后半部分元素
move_backward(queue, index, queue->size - index);
queue->tail = (queue->tail + 1) % queue->capacity; // 尾指针后移
}
// 在空出的位置插入数据
if (data) assign(at((queue->head + index) % (queue->capacity)), data);
queue->size++;
return 1;
}
/**
* \brief 指定位置删除元素
* \param[in] queue: 队列对象指针
* \param[in] index: 删除位置索引(0=队头, size-1=队尾)
* \param[out] data: 数据接收地址(NULL表示丢弃数据)
* \return 1=成功, 0=失败(索引越界或队列为空)
*
* \details 删除指定位置元素,后续元素前移。
* 自动选择最优移动方向。
* 时间复杂度O(min(index, size-index))。
*/
int queue_erase(queue queue, int index, void* data)
{
if (!queue) return 0;
if (index < 0 || index >= queue->size) return 0; // 索引越界检查
if (queue->size == 0) return 0; // 队列为空
// 保存被删除元素(如果需要)
if (data) assign(data, at((queue->head + index) % (queue->capacity)));
// 根据删除位置选择最优移动方向
if (index <= queue->size / 2) {
// 向后移动前半部分元素
move_backward(queue, 0, index);
queue->head = (queue->head + 1) % queue->capacity; // 头指针后移
} else {
// 向前移动后半部分元素
move_forward(queue, index + 1, queue->size - index - 1);
queue->tail = (queue->tail + queue->capacity - 1) % queue->capacity; // 尾指针前移
}
queue->size--;
return 1;
}
/**
* \brief 清空队列
* \param[in] queue: 队列对象指针
*
* \details 重置队列状态(头尾指针归零,大小归零)。
* 不释放存储内存,保持队列容量不变。
*/
void queue_clear(queue queue)
{
if (!queue) return;
queue->tail = 0;
queue->head = 0;
queue->size = 0;
}
/**
* \brief 获取元素地址
* \param[in] queue: 队列对象指针
* \param[in] index: 元素索引(0=队头, size-1=队尾)
* \return 元素地址(失败返回NULL
*
* \details 获取队列中指定位置元素的直接指针。
* 可用于直接修改元素值(无需复制)。
* \warning 返回的指针在队列结构修改后可能失效。
*/
void* queue_data(queue queue, int index)
{
if (!queue) return 0;
if (index < 0 || index >= queue->size) return 0; // 索引越界检查
return (void*)at((queue->head + index) % (queue->capacity));
}
+119
View File
@@ -0,0 +1,119 @@
#ifndef _ALGO_QUEUE_H_
#define _ALGO_QUEUE_H_
/* 队列类型定义 */
typedef struct QUEUE
{
void* base; /* 数据存储区的基地址 */
int dsize; /* 每个数据元素的大小(字节) */
int capacity; /* 队列的总容量(最大元素数量) */
int size; /* 当前队列中的元素数量 */
int head; /* 队头索引(指向第一个元素) */
int tail; /* 队尾索引(指向下一个插入位置) */
} *queue; // 定义queue为指向该结构的指针类型
/**
* \brief 创建并初始化一个队列
* \param[in] type: 队列元素的数据类型
* \param[in] capacity: 队列容量
* \return 初始化完成的队列对象
*
* \note 使用复合字面量在栈上创建队列对象
* \example queue(int, 10) 创建容量为10的整型队列
*/
#define queue(type, capacity) (&(struct QUEUE){(type[capacity]){0},sizeof(type),capacity,0,0,0})
// 函数声明
int queue_push(queue queue, void* data);
int queue_push2(queue queue, void* data);
int queue_pop(queue queue, void* data);
int queue_insert(queue queue, int index, void* data);
int queue_erase(queue queue, int index, void* data);
void queue_clear(queue queue);
void* queue_data(queue queue, int index);
/**
* \brief 访问队列指定位置的元素
* \param[in] queue: 队列对象
* \param[in] type: 元素数据类型
* \param[in] i: 元素位置索引(0-based
* \return 指定元素的左值引用
*
* \example queue_at(q, int, 0) = 42; // 设置队首元素
*/
#define queue_at(queue, type, i) (*(type *)queue_data((queue),(i)))
/**
* \brief 在队头插入元素
* \param[in] queue: 队列对象
* \param[in] data: 待插入数据地址(NULL表示不赋值)
* \return 操作成功状态(1成功/0失败)
*/
#define queue_push_front(queue, data) queue_insert((queue), 0, data)
/**
* \brief 在队尾插入元素
* \param[in] queue: 队列对象
* \param[in] data: 待插入数据地址(NULL表示不赋值)
* \return 操作成功状态(1成功/0失败)
*/
#define queue_push_back(queue, data) queue_push2((queue), data)
/**
* \brief 从队头弹出元素
* \param[in] queue: 队列对象
* \param[out] data: 接收弹出数据的地址(NULL表示不保存)
* \return 操作成功状态(1成功/0失败)
*/
#define queue_pop_front(queue, data) queue_pop((queue), data)
/**
* \brief 从队尾弹出元素
* \param[in] queue: 队列对象
* \param[out] data: 接收弹出数据的地址(NULL表示不保存)
* \return 操作成功状态(1成功/0失败)
*/
#define queue_pop_back(queue, data) queue_erase((queue), (queue)->size - 1, data)
/**
* \brief 获取队列当前元素数量
* \param[in] queue: 队列对象
* \return 队列中的元素数量
*/
#define queue_size(queue) ((queue)->size)
/**
* \brief 获取队列总容量
* \param[in] queue: 队列对象
* \return 队列的最大容量
*/
#define queue_capacity(queue) ((queue)->capacity)
/**
* \brief 检查队列是否为空
* \param[in] queue: 队列对象
* \return 0表示非空,非0表示空
*/
#define queue_empty(queue) ((queue)->size == 0)
/**
* \brief 检查队列是否已满
* \param[in] queue: 队列对象
* \return 0表示未满,非0表示已满
*/
#define queue_full(queue) ((queue)->size == (queue)->capacity)
/**
* \brief 创建字面量的地址包装
* \param[in] type: 数据类型(如int/float等)
* \param[in] value: 字面量值
* \return 包含该值的临时数组地址
*
* \note 用于将字面量转换为指针参数
* \example queue_push(q, literal(int, 42));
*/
#ifndef literal
#define literal(type, value) ((type[1]){value})
#endif
#endif
+159
View File
@@ -0,0 +1,159 @@
#include "app.h"
#include "app_timer.h"
#include "app_leakage.h"
#include "stdio.h"
#include "string.h"
#include "bsp_Uart.h"
#include "bsp_Wdg.h"
#include "bsp_Led.h"
#include "bsp_Flash.h"
#include "bsp_W5500.h"
#include "bsp_w25q.h"
#include "bsp_DS1302.h"
#include "bsp_relay.h"
#include "bsp_buzzer.h"
#include "proto_modbus_master_leakage.h"
#include "proto_modbus_slave_ex.h"
#include "gui_tjc_hmi.h"
const char *HwVersion = "V1.0";
char SwVersion[24] = "V0.001.0";
void task_idle(void);
void task_10ms(void);
void task_50ms(void);
void task_100ms(void);
void task_200ms(void);
void task_500ms(void);
void task_1s(void);
void task_2s(void);
#define APP_TIMER_TASK_NUM (sizeof(app_timer_task) / sizeof(app_timer_class_t))
/*定义任务*/
app_timer_class_t app_timer_task[] =
{
{0, 1, 1, task_idle }, /*空闲任务一直执行*/
{0, 3, 10, task_10ms },
{0, 7, 50, task_50ms },
{0, 11, 100, task_100ms },
{0, 13, 200, task_200ms },
{0, 17, 500, task_500ms },
{0, 19, 1000, task_1s },
{0, 23, 2000, task_2s },
};
/******************************************
* 函数: AppInit
* 功能: 初始化
* 参数: 无
* 返回: 无
* 描述: 无
******************************************/
void app_init(void)
{
/*flash*/
Usr_Flash.Init();
/*串口初始化*/
com_uart1.init(&com_uart1);
com_uart2.init(&com_uart2);
com_uart3.init(&com_uart3);
com_uart4.init(&com_uart4);
com_uart6.init(&com_uart6);
/*网口*/
W5500.Init();
/*屏幕通讯*/
tjc_hmi.init();
/*modbus协议*/
modbus_slave_ex.init();
/*子系统*/
modbus_leakage[APP_COM1].init(&modbus_leakage[APP_COM1]);
modbus_leakage[APP_COM2].init(&modbus_leakage[APP_COM2]);
modbus_leakage[APP_COM3].init(&modbus_leakage[APP_COM3]);
modbus_leakage[APP_COM4].init(&modbus_leakage[APP_COM4]);
/*外设通讯*/
DS1302.Init();
relay.init();
buzzer.init();
led.init();
/*分时复用,时间片轮询*/
app_timer.init(APP_TIMER_TASK_NUM,app_timer_task);
//Wdg.Init();
}
/******************************************
* 函数: App_task
* 功能: 分时复用
* 参数: 无
* 返回: 无
* 描述: 主循环中调用
******************************************/
void app_task(void)
{
app_timer.task();
task_idle();
W5500.Task();
}
/*空闲执行的函数*/
void task_idle(void)
{
com_uart1.rx_task(&com_uart1);
com_uart2.rx_task(&com_uart2);
com_uart3.rx_task(&com_uart3);
com_uart4.rx_task(&com_uart4);
com_uart6.rx_task(&com_uart6);
}
void task_10ms(void)
{
}
void task_50ms(void)
{
}
void task_100ms(void)
{
}
void task_200ms(void)
{
}
void task_500ms(void)
{
led.task();
//tdlas.tx_task();
}
void task_1s(void)
{
leakage.task();
DS1302.Task();
buzzer.task();
relay.task();
}
void task_2s(void)
{
}
+15
View File
@@ -0,0 +1,15 @@
#ifndef _APP_H_
#define _APP_H_
extern const char *HwVersion;
extern char SwVersion[24];
void app_init(void);
void app_task(void);
#endif
+355
View File
@@ -0,0 +1,355 @@
#include "app_alarm.h"
#include <string.h>
#include "bsp_w25q.h"
static void history_clear_all(void);
static u8 history_read_record(u32 record_index, app_leakage_history_alarm_t *record);
static void history_init(void);
static void history_save_metadata(void);
app_leakage_t leakage =
{
.region_num = 0,
.sub_device_num = 0,
.init = NULL,
.task = app_leakage_task
};
app_leakage_t *p_leakage = &leakage;
app_hitory_t history =
{
.read_history = history_read_record,
.clean_history = history_clear_all,
.init_history = history_init
};
/*区域分类,将同一区域名的设备划分到一起*/
void app_leakage_region_classify(void)
{
u16 i,j;
u8 add_region_flag;
/*数量及相关数据清零*/
p_leakage->region_num = 0;
p_leakage->sub_device_num = 0;
memset(p_leakage->region_data,0,sizeof(p_leakage->region_data));
/*遍历子系统*/
for(i=0;i<APP_LEAKAGE_SUB_DEVICE_NUM;i++)
{
add_region_flag = 1; /*添加新区域*/
/*设备使能*/
if(ENABLE == p_leakage->sub_device_data[i].flash_data.state)
{
p_leakage->sub_device_num++;/*子系统总数量++*/
/*遍历区域*/
for(j=0;j<APP_LEAKAGE_SUB_DEVICE_NUM;j++)
{
if(0 == memcmp(p_leakage->region_data[j].name,p_leakage->sub_device_data[i].flash_data.region_name, APP_LEAKAGE_STRING_NANE_LEN))/*名称相同*/
{
/*添加子设备*/
p_leakage->region_data[j].sub_device_index[p_leakage->region_data[j].leakage_num] = i;/*绑定子设备索引*/
p_leakage->region_data[j].sub_device_num++; /*区域中子系统数据++*/
add_region_flag = 0;/*不添加新区域*/
break;
}
}
/*没有找到相同名称*/
if(add_region_flag)/*添加新区域*/
{
/*复制名称*/
memcpy(p_leakage->region_data[p_leakage->region_num].name,p_leakage->sub_device_data[i].flash_data.region_name, APP_LEAKAGE_STRING_NANE_LEN);
p_leakage->region_data[p_leakage->region_num].sub_device_index[p_leakage->region_data[p_leakage->region_num].leakage_num] = i;/*绑定子设备索引*/
p_leakage->region_data[p_leakage->region_num].sub_device_num++; /*区域中子系统数据++*/
p_leakage->region_num++; /*区域数量++*/
}
}
}
}
/*异常状态设备数量统计*/
void app_leakage_task(void)
{
static u16 prev_ch_state[APP_LEAKAGE_SUB_DEVICE_NUM][APP_LEAKAGE_SUB_DEVICE_CH_NUM] = {0};
u16 i, j, k, sub_device_index;
static u8 initialized = 0;
/* 初始化历史模块 */
if(!initialized)
{
history.init_history();
initialized = 1;
}
/* 初始化区域异常统计 */
for(i = 0; i < p_leakage->region_num; i++)
{
p_leakage->region_data[i].leakage_num = 0;
p_leakage->region_data[i].open_num = 0;
p_leakage->region_data[i].time_out_num = 0;
}
/* 检测状态变化并统计异常数量 */
for(i = 0; i < p_leakage->region_num; i++)
{
for(j = 0; j < p_leakage->region_data[i].sub_device_num; j++)
{
sub_device_index = p_leakage->region_data[i].sub_device_index[j];
/* 检查设备是否启用 */
if(p_leakage->sub_device_data[sub_device_index].flash_data.state != ENABLE)
{
continue;
}
for(k = 0; k < APP_LEAKAGE_SUB_DEVICE_CH_NUM; k++)
{
u16 current_state = p_leakage->sub_device_data[sub_device_index].ch_data[k].state;
u16 prev_state = prev_ch_state[sub_device_index][k];
u16 leak_distance = p_leakage->sub_device_data[sub_device_index].ch_data[k].distance;
/* 检测状态变化并记录历史报警 */
if((current_state & APP_LEAKAGE_SUB_DEVICE_STATE_LEAKAGE) &&
!(prev_state & APP_LEAKAGE_SUB_DEVICE_STATE_LEAKAGE))
{
/* 漏液报警开始 - 记录历史报警 */
history_add_alarm_record(i, sub_device_index, k, APP_LEAKAGE_SUB_DEVICE_STATE_LEAKAGE, leak_distance);
}
if((current_state & APP_LEAKAGE_SUB_DEVICE_STATE_OPEN) &&
!(prev_state & APP_LEAKAGE_SUB_DEVICE_STATE_OPEN))
{
/* 断带报警开始 - 记录历史报警 */
history_add_alarm_record(i, sub_device_index, k, APP_LEAKAGE_SUB_DEVICE_STATE_OPEN, 0);
}
if((current_state & APP_LEAKAGE_SUB_DEVICE_STATE_TIME_OUT) &&
!(prev_state & APP_LEAKAGE_SUB_DEVICE_STATE_TIME_OUT))
{
/* 通讯超时报警开始 - 记录历史报警 */
history_add_alarm_record(i, sub_device_index, k, APP_LEAKAGE_SUB_DEVICE_STATE_TIME_OUT, 0);
}
/* 更新历史状态 */
prev_ch_state[sub_device_index][k] = current_state;
}
/* 统计区域异常设备数量 - 按设备统计 */
for(k = 0; k < APP_LEAKAGE_SUB_DEVICE_CH_NUM; k++)
{
u16 current_state = p_leakage->sub_device_data[sub_device_index].ch_data[k].state;
if(current_state & APP_LEAKAGE_SUB_DEVICE_STATE_TIME_OUT)
{
p_leakage->region_data[i].time_out_num++;
continue; /* 通讯超时,设备已离线,不再检查其他异常 */
}
if(current_state & APP_LEAKAGE_SUB_DEVICE_STATE_OPEN)
{
p_leakage->region_data[i].open_num++;
}
if(current_state & APP_LEAKAGE_SUB_DEVICE_STATE_LEAKAGE)
{
p_leakage->region_data[i].leakage_num++;
}
}
}
}
}
/* 获取当前时间 */
static void get_current_time(u8 *time_buffer)
{
// RTC_TimeTypeDef sTime;
// RTC_DateTypeDef sDate;
//
// /* 获取RTC时间 */
// HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN);
// HAL_RTC_GetDate(&hrtc, &sDate, RTC_FORMAT_BIN);
//
// /* 年: 2字节 (例如: 2024 -> 0x07 0xE8) */
// uint16_t year = 2000 + sDate.Year; /* RTC年份通常从2000开始 */
// time_buffer[0] = (year >> 8) & 0xFF; /* 高字节 */
// time_buffer[1] = year & 0xFF; /* 低字节 */
// time_buffer[2] = sDate.Month; /* 月 */
// time_buffer[3] = sDate.Date; /* 日 */
// time_buffer[4] = sTime.Hours; /* 时 */
// time_buffer[5] = sTime.Minutes; /* 分 */
}
/* 从Flash读取历史报警元数据 */
static void history_read_metadata(void)
{
app_leakage_history_metadata_t temp_metadata;
w25q32.read(W25Q32_HISTORY_ALARM_METADATA_ADDR,
(uint8_t*)&temp_metadata,
sizeof(app_leakage_history_metadata_t));
if(temp_metadata.total_records <= temp_metadata.max_records &&
temp_metadata.write_index < temp_metadata.max_records)
{
/* 数据有效,复制到全局变量 */
memcpy(&leakage.history_metadata, &temp_metadata, sizeof(app_leakage_history_metadata_t));
}
else
{
/* 数据无效,初始化 */
memset(&leakage.history_metadata, 0, sizeof(app_leakage_history_metadata_t));
leakage.history_metadata.max_records = MAX_HISTORY_ALARM_RECORDS;
/* 保存到Flash */
history_save_metadata();
}
}
/* 保存历史报警元数据到Flash */
static void history_save_metadata(void)
{
/* 擦除元数据扇区 */
w25q32_sector_erase(W25Q32_HISTORY_ALARM_METADATA_ADDR);
/* 写入元数据 */
w25q32.write(W25Q32_HISTORY_ALARM_METADATA_ADDR,
(uint8_t*)&leakage.history_metadata,
sizeof(app_leakage_history_metadata_t));
}
/* 计算记录在Flash中的地址 */
static uint32_t history_calc_record_addr(u32 record_index)
{
return W25Q32_HISTORY_ALARM_DATA_ADDR +
(record_index * HISTORY_ALARM_RECORD_SIZE);
}
/* 获取记录所在的扇区地址 */
static uint32_t history_calc_sector_addr(u32 record_index)
{
uint32_t record_addr = history_calc_record_addr(record_index);
return record_addr & ~(W25Q32_SECTOR_SIZE - 1); /* 4K对齐 */
}
/* 添加历史报警记录 */
void history_add_alarm_record(u8 region_idx, u8 device_idx, u8 channel, u16 alarm_type, u16 leak_distance)
{
app_leakage_history_alarm_t new_alarm;
uint32_t write_addr;
/* 填充报警记录 */
memset(&new_alarm, 0, sizeof(app_leakage_history_alarm_t));
/* 区域名 */
if(region_idx < leakage.region_num)
{
memcpy(new_alarm.region_name, leakage.region_data[region_idx].name,
APP_LEAKAGE_STRING_NANE_LEN);
}
/* 设备ID和名称 */
if(device_idx < APP_LEAKAGE_SUB_DEVICE_NUM)
{
new_alarm.device_id = leakage.sub_device_data[device_idx].flash_data.modbus_id;
memcpy(new_alarm.device_name, leakage.sub_device_data[device_idx].flash_data.device_name,
APP_LEAKAGE_STRING_NANE_LEN);
}
/* 报警类型、通道和漏液距离 */
new_alarm.alarm_type = alarm_type;
new_alarm.channel = channel;
new_alarm.leak_distance = leak_distance;
/* 开始时间 */
get_current_time(new_alarm.start_time);
/* 计算写入地址 */
write_addr = history_calc_record_addr(leakage.history_metadata.write_index);
/* 检查是否需要擦除新扇区 */
uint32_t current_sector = history_calc_sector_addr(leakage.history_metadata.write_index);
uint32_t prev_sector = history_calc_sector_addr(
(leakage.history_metadata.write_index == 0) ?
leakage.history_metadata.max_records - 1 :
leakage.history_metadata.write_index - 1);
/* 如果切换到新扇区,需要擦除 */
if(current_sector != prev_sector)
{
w25q32_sector_erase(current_sector);
}
/* 写入记录 */
w25q32.write(write_addr, (uint8_t*)&new_alarm, HISTORY_ALARM_RECORD_SIZE);
/* 更新元数据 */
leakage.history_metadata.write_index++;
if(leakage.history_metadata.write_index >= leakage.history_metadata.max_records)
{
leakage.history_metadata.write_index = 0;
}
if(leakage.history_metadata.total_records < leakage.history_metadata.max_records)
{
leakage.history_metadata.total_records++;
}
/* 保存元数据 */
history_save_metadata();
}
/* 读取历史报警记录 */
static u8 history_read_record(u32 record_index, app_leakage_history_alarm_t *record)
{
if(record_index >= leakage.history_metadata.total_records)
{
return 0; /* 记录索引无效 */
}
/* 计算实际存储索引(考虑循环队列) */
uint32_t actual_index;
if(leakage.history_metadata.total_records == leakage.history_metadata.max_records)
{
/* 缓冲区已满,计算相对索引 */
actual_index = (leakage.history_metadata.write_index + record_index) %
leakage.history_metadata.max_records;
}
else
{
/* 缓冲区未满,直接读取 */
actual_index = record_index;
}
uint32_t read_addr = history_calc_record_addr(actual_index);
w25q32.read(read_addr, (uint8_t*)record, HISTORY_ALARM_RECORD_SIZE);
return 1;
}
/* 清空所有历史报警记录 */
static void history_clear_all(void)
{
/* 重置元数据 */
memset(&leakage.history_metadata, 0, sizeof(app_leakage_history_metadata_t));
leakage.history_metadata.max_records = MAX_HISTORY_ALARM_RECORDS;
/* 保存元数据 */
history_save_metadata();
/* 擦除所有数据扇区(可选) */
for(uint32_t i = 0; i < HISTORY_ALARM_SECTORS_NEEDED; i++)
{
uint32_t sector_addr = W25Q32_HISTORY_ALARM_DATA_ADDR + i * W25Q32_SECTOR_SIZE;
w25q32_sector_erase(sector_addr);
}
}
/* 初始化历史报警模块 */
static void history_init(void)
{
/* 读取元数据 */
history_read_metadata();
}
+99
View File
@@ -0,0 +1,99 @@
#ifndef _APP_ALARM_H_
#define _APP_ALARM_H_
#include "main.h"
#define ENABLE (1)
#define DISABLE (0)
#define APP_LEAKAGE_SUB_DEVICE_STATE_LEAKAGE (0x0001) /*漏液状态*/
#define APP_LEAKAGE_SUB_DEVICE_STATE_OPEN (0x0002) /*断带状态*/
#define APP_LEAKAGE_SUB_DEVICE_STATE_TIME_OUT (0xf000) /*通讯超时*/
#define APP_LEAKAGE_STRING_NANE_LEN (10)
#define APP_LEAKAGE_SUB_DEVICE_NUM (32)
#define APP_LEAKAGE_SUB_DEVICE_CH_NUM (4)
void app_leakage_task(void);
void app_leakage_region_classify(void);
void history_add_alarm_record(u8 region_idx, u8 device_idx, u8 channel, u16 alarm_type, u16 leak_distance);
/*子设备存储的参数*/
typedef struct
{
u8 state; /*状态 使能 非使能*/
u8 com_port; /*端口*/
u8 modbus_id; /*modbus id*/
u8 device_name[APP_LEAKAGE_STRING_NANE_LEN]; /*设备名*/
u8 region_name[APP_LEAKAGE_STRING_NANE_LEN]; /*区域名*/
}app_leakage_sub_device_flash_data_t;
/*子设备信息*/
typedef struct
{
app_leakage_sub_device_flash_data_t flash_data; /*flash存储数据*/
struct
{
u16 state; /*状态*/
u16 distance; /*漏液距离*/
}ch_data[APP_LEAKAGE_SUB_DEVICE_CH_NUM]; /*通道数据*/
u8 heartbeat; /*心跳包,0-59循环*/
u8 test_mode; /*测试模式,0=正常,1-4=测试对应通道*/
}app_leakage_sub_device_class_t;
/*区域信息*/
typedef struct
{
u8 leakage_num; /*漏液数量*/
u8 open_num; /*断带数量*/
u8 time_out_num; /*通讯超时数量*/
u8 sub_device_num; /*设备总数量*/
u8 name[APP_LEAKAGE_STRING_NANE_LEN]; /*区域名称*/
u8 sub_device_index[APP_LEAKAGE_SUB_DEVICE_NUM]; /*设备的索引*/
}app_leakage_region_data_class_t;
/* 历史报警记录结构 */
typedef struct
{
u8 region_name[APP_LEAKAGE_STRING_NANE_LEN]; /* 区域名 */
u8 device_id; /* 设备ID */
u8 device_name[APP_LEAKAGE_STRING_NANE_LEN]; /* 设备名称 */
u16 alarm_type; /* 报警类型 */
u8 start_time[6]; /* 开始时间: 年(2字节)月日时分 */
u16 leak_distance; /* 漏液距离 (0表示非漏液报警) */
u8 channel; /* 通道号 (0-3) */
} app_leakage_history_alarm_t;
/* 历史报警管理结构 */
typedef struct
{
u32 total_records; /* 总记录数 */
u32 write_index; /* 写指针 */
u32 read_index; /* 读指针 */
u32 max_records; /* 最大记录数 */
} app_leakage_history_metadata_t;
typedef struct
{
u8 region_num;
u8 sub_device_num;
app_leakage_region_data_class_t region_data[APP_LEAKAGE_SUB_DEVICE_NUM];
app_leakage_sub_device_class_t sub_device_data[APP_LEAKAGE_SUB_DEVICE_NUM];
app_leakage_history_metadata_t history_metadata;
void (*init)(void); /*初始化*/
void (*task)(void); /*执行任务*/
}app_leakage_t;
typedef struct
{
u8 (*read_history)(u32, app_leakage_history_alarm_t *);
void (*clean_history)(void);
void (*init_history)(void);
}app_hitory_t;
extern app_hitory_t history;
#endif
+77
View File
@@ -0,0 +1,77 @@
#include "app_com.h"
#include "app_leakage.h"
#include "proto_modbus_master_leakage.h"
/*com口对应的串口*/
bsp_uart_t *com_to_uart[APP_COM_NUM] =
{
&com_uart4,
&com_uart2,
&com_uart3,
&com_uart1,
};
static void app_com_uart_baud_rate_set(app_com_class_t * p_com,u16 baud_rate);
static void app_com_class_update(void );
static void app_com_init(app_com_class_t * p_com);
app_com_t app_com=
{
};
static void app_com_init(app_com_class_t * p_com)
{
if(p_com == &app_com.com[APP_COM1])
p_com->com_uart = com_to_uart[APP_COM1];
else if(p_com == &app_com.com[APP_COM2])
p_com->com_uart = com_to_uart[APP_COM2];
else if(p_com == &app_com.com[APP_COM3])
p_com->com_uart = com_to_uart[APP_COM3];
else if(p_com == &app_com.com[APP_COM4])
p_com->com_uart = com_to_uart[APP_COM4];
}
/*串口配置*/
static void app_com_uart_baud_rate_set(app_com_class_t * p_com,u16 baud_rate)
{
p_com->com_uart->set.baud_rate(p_com->com_uart,baud_rate);
}
/*将同一com口的设备进行划分*/
static void app_com_class_update(void )
{
u16 i,j;
u8 com_index,id;
/********************************************总数清零******************************************************/
for(i=0;i<APP_COM_NUM;i++)
{
modbus_leakage[i].sensor_num = 0;
}
/*遍历子系统*/
for(i=0;i<APP_LEAKAGE_SUB_DEVICE_NUM;i++)
{
/*设备使能*/
if(ENABLE == leakage.sub_device_data[i].flash_data.state)
{
/********************************************COM口划分******************************************************/
com_index = leakage.sub_device_data[i].flash_data.com;
id = leakage.sub_device_data[i].flash_data.modbus_id;
/*绑定modbus id*/
modbus_leakage[com_index].sensor[modbus_leakage[com_index].sensor_num].comm.id = id;
/*绑定子设备索引索引*/
modbus_leakage[com_index].sensor[modbus_leakage[com_index].sensor_num].comm.leakage_data_index = i;
/*comm口设备总数++*/
modbus_leakage[com_index].sensor_num++;
}
}
}
+43
View File
@@ -0,0 +1,43 @@
#ifndef _APP_COM_H_
#define _APP_COM_H_
#include "main.h"
#include "app_leakage.h"
#include "bsp_uart.h"
#define APP_COM_NUM (4)
#define APP_COM1 (0)
#define APP_COM2 (1)
#define APP_COM3 (2)
#define APP_COM4 (3)
typedef struct
{
u8 baudrate; /*波特率*/
}app_com_flash_data_t;
typedef struct app_com_class_t app_com_class_t;
struct app_com_class_t
{
app_com_flash_data_t flash_data; /*flash数据*/
bsp_uart_t *com_uart; /*绑定的实际物理串口*/
struct
{
void (*baud_rate)(app_com_class_t *,u16); /*设置波特率*/
}set;
void (*init)(app_com_class_t *); /*初始化*/
};
typedef struct
{
app_com_class_t com[APP_COM_NUM];
void (*class_update)(void ); /*com区域分类*/
}app_com_t;
extern app_com_t app_com;
extern bsp_uart_t *com_to_uart[APP_COM_NUM];
#endif
+359
View File
@@ -0,0 +1,359 @@
#include "app_leakage.h"
#include <string.h>
#include "bsp_w25q.h"
static void history_clear_all(void);
static u8 history_read_record(u32 record_index, app_leakage_history_alarm_t *record);
static void history_init(void);
static void history_save_metadata(void);
app_leakage_t leakage =
{
.region_num = 0,
.sub_device_num = 0,
.init = NULL,
.task = app_leakage_task
};
app_leakage_t *p_leakage = &leakage;
app_hitory_t history =
{
.read_history = history_read_record,
.clean_history = history_clear_all,
.init_history = history_init
};
/*区域分类,将同一区域名的设备划分到一起*/
void app_leakage_region_classify(void)
{
u16 i,j;
u8 add_region_flag;
/*数量及相关数据清零*/
p_leakage->region_num = 0;
p_leakage->sub_device_num = 0;
memset(p_leakage->region_data,0,sizeof(p_leakage->region_data));
/*遍历子系统*/
for(i=0;i<APP_LEAKAGE_SUB_DEVICE_NUM;i++)
{
add_region_flag = 1; /*添加新区域*/
/*设备使能*/
if(ENABLE == p_leakage->sub_device_data[i].flash_data.state)
{
p_leakage->sub_device_num++;/*子系统总数量++*/
/********************************************区域划分******************************************************/
/*遍历区域*/
for(j=0;j<APP_LEAKAGE_SUB_DEVICE_NUM;j++)
{
if(0 == memcmp(p_leakage->region_data[j].name,p_leakage->sub_device_data[i].flash_data.region_name, APP_LEAKAGE_STRING_NANE_LEN))/*名称相同*/
{
/*添加子设备*/
p_leakage->region_data[j].sub_device_index[p_leakage->region_data[j].leakage_num] = i;/*绑定子设备索引*/
p_leakage->region_data[j].sub_device_num++; /*区域中子系统数据++*/
add_region_flag = 0;/*不添加新区域*/
break;
}
}
/*没有找到相同名称*/
if(add_region_flag)/*添加新区域*/
{
/*复制名称*/
memcpy(p_leakage->region_data[p_leakage->region_num].name,p_leakage->sub_device_data[i].flash_data.region_name, APP_LEAKAGE_STRING_NANE_LEN);
p_leakage->region_data[p_leakage->region_num].sub_device_index[p_leakage->region_data[p_leakage->region_num].leakage_num] = i;/*绑定子设备索引*/
p_leakage->region_data[p_leakage->region_num].sub_device_num++; /*区域中子系统数据++*/
p_leakage->region_num++; /*区域数量++*/
}
}
}
}
/*异常状态设备数量统计*/
void app_leakage_task(void)
{
static u16 prev_ch_state[APP_LEAKAGE_SUB_DEVICE_NUM][APP_LEAKAGE_SUB_DEVICE_CH_NUM] = {0};
u16 i, j, k, sub_device_index;
static u8 initialized = 0;
/* 初始化历史模块 */
if(!initialized)
{
history.init_history();
initialized = 1;
}
/* 初始化区域异常统计 */
for(i = 0; i < p_leakage->region_num; i++)
{
p_leakage->region_data[i].leakage_num = 0;
p_leakage->region_data[i].open_num = 0;
p_leakage->region_data[i].time_out_num = 0;
}
/* 检测状态变化并统计异常数量 */
for(i = 0; i < p_leakage->region_num; i++)
{
for(j = 0; j < p_leakage->region_data[i].sub_device_num; j++)
{
sub_device_index = p_leakage->region_data[i].sub_device_index[j];
/* 检查设备是否启用 */
if(p_leakage->sub_device_data[sub_device_index].flash_data.state != ENABLE)
{
continue;
}
for(k = 0; k < APP_LEAKAGE_SUB_DEVICE_CH_NUM; k++)
{
u16 current_state = p_leakage->sub_device_data[sub_device_index].ch_data[k].state;
u16 prev_state = prev_ch_state[sub_device_index][k];
u16 leak_distance = p_leakage->sub_device_data[sub_device_index].ch_data[k].distance;
/* 检测状态变化并记录历史报警 */
if((current_state & APP_LEAKAGE_SUB_DEVICE_STATE_LEAKAGE) &&
!(prev_state & APP_LEAKAGE_SUB_DEVICE_STATE_LEAKAGE))
{
/* 漏液报警开始 - 记录历史报警 */
history_add_alarm_record(i, sub_device_index, k, APP_LEAKAGE_SUB_DEVICE_STATE_LEAKAGE, leak_distance);
}
if((current_state & APP_LEAKAGE_SUB_DEVICE_STATE_OPEN) &&
!(prev_state & APP_LEAKAGE_SUB_DEVICE_STATE_OPEN))
{
/* 断带报警开始 - 记录历史报警 */
history_add_alarm_record(i, sub_device_index, k, APP_LEAKAGE_SUB_DEVICE_STATE_OPEN, 0);
}
if((current_state & APP_LEAKAGE_SUB_DEVICE_STATE_TIME_OUT) &&
!(prev_state & APP_LEAKAGE_SUB_DEVICE_STATE_TIME_OUT))
{
/* 通讯超时报警开始 - 记录历史报警 */
history_add_alarm_record(i, sub_device_index, k, APP_LEAKAGE_SUB_DEVICE_STATE_TIME_OUT, 0);
}
/* 更新历史状态 */
prev_ch_state[sub_device_index][k] = current_state;
}
/* 统计区域异常设备数量 - 按设备统计 */
for(k = 0; k < APP_LEAKAGE_SUB_DEVICE_CH_NUM; k++)
{
u16 current_state = p_leakage->sub_device_data[sub_device_index].ch_data[k].state;
if(current_state & APP_LEAKAGE_SUB_DEVICE_STATE_TIME_OUT)
{
p_leakage->region_data[i].time_out_num++;
continue; /* 通讯超时,设备已离线,不再检查其他异常 */
}
if(current_state & APP_LEAKAGE_SUB_DEVICE_STATE_OPEN)
{
p_leakage->region_data[i].open_num++;
}
if(current_state & APP_LEAKAGE_SUB_DEVICE_STATE_LEAKAGE)
{
p_leakage->region_data[i].leakage_num++;
}
}
}
}
}
/* 获取当前时间 */
static void get_current_time(u8 *time_buffer)
{
// RTC_TimeTypeDef sTime;
// RTC_DateTypeDef sDate;
//
// /* 获取RTC时间 */
// HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN);
// HAL_RTC_GetDate(&hrtc, &sDate, RTC_FORMAT_BIN);
//
// /* 年: 2字节 (例如: 2024 -> 0x07 0xE8) */
// uint16_t year = 2000 + sDate.Year; /* RTC年份通常从2000开始 */
// time_buffer[0] = (year >> 8) & 0xFF; /* 高字节 */
// time_buffer[1] = year & 0xFF; /* 低字节 */
// time_buffer[2] = sDate.Month; /* 月 */
// time_buffer[3] = sDate.Date; /* 日 */
// time_buffer[4] = sTime.Hours; /* 时 */
// time_buffer[5] = sTime.Minutes; /* 分 */
}
/* 从Flash读取历史报警元数据 */
static void history_read_metadata(void)
{
app_leakage_history_metadata_t temp_metadata;
w25q32.read(W25Q32_HISTORY_ALARM_METADATA_ADDR,
(uint8_t*)&temp_metadata,
sizeof(app_leakage_history_metadata_t));
if(temp_metadata.total_records <= temp_metadata.max_records &&
temp_metadata.write_index < temp_metadata.max_records)
{
/* 数据有效,复制到全局变量 */
memcpy(&leakage.history_metadata, &temp_metadata, sizeof(app_leakage_history_metadata_t));
}
else
{
/* 数据无效,初始化 */
memset(&leakage.history_metadata, 0, sizeof(app_leakage_history_metadata_t));
leakage.history_metadata.max_records = MAX_HISTORY_ALARM_RECORDS;
/* 保存到Flash */
history_save_metadata();
}
}
/* 保存历史报警元数据到Flash */
static void history_save_metadata(void)
{
/* 擦除元数据扇区 */
w25q32_sector_erase(W25Q32_HISTORY_ALARM_METADATA_ADDR);
/* 写入元数据 */
w25q32.write(W25Q32_HISTORY_ALARM_METADATA_ADDR,
(uint8_t*)&leakage.history_metadata,
sizeof(app_leakage_history_metadata_t));
}
/* 计算记录在Flash中的地址 */
static uint32_t history_calc_record_addr(u32 record_index)
{
return W25Q32_HISTORY_ALARM_DATA_ADDR +
(record_index * HISTORY_ALARM_RECORD_SIZE);
}
/* 获取记录所在的扇区地址 */
static uint32_t history_calc_sector_addr(u32 record_index)
{
uint32_t record_addr = history_calc_record_addr(record_index);
return record_addr & ~(W25Q32_SECTOR_SIZE - 1); /* 4K对齐 */
}
/* 添加历史报警记录 */
void history_add_alarm_record(u8 region_idx, u8 device_idx, u8 channel, u16 alarm_type, u16 leak_distance)
{
app_leakage_history_alarm_t new_alarm;
uint32_t write_addr;
/* 填充报警记录 */
memset(&new_alarm, 0, sizeof(app_leakage_history_alarm_t));
/* 区域名 */
if(region_idx < leakage.region_num)
{
memcpy(new_alarm.region_name, leakage.region_data[region_idx].name,
APP_LEAKAGE_STRING_NANE_LEN);
}
/* 设备ID和名称 */
if(device_idx < APP_LEAKAGE_SUB_DEVICE_NUM)
{
new_alarm.device_id = leakage.sub_device_data[device_idx].flash_data.modbus_id;
memcpy(new_alarm.device_name, leakage.sub_device_data[device_idx].flash_data.device_name,
APP_LEAKAGE_STRING_NANE_LEN);
}
/* 报警类型、通道和漏液距离 */
new_alarm.alarm_type = alarm_type;
new_alarm.channel = channel;
new_alarm.leak_distance = leak_distance;
/* 开始时间 */
get_current_time(new_alarm.start_time);
/* 计算写入地址 */
write_addr = history_calc_record_addr(leakage.history_metadata.write_index);
/* 检查是否需要擦除新扇区 */
uint32_t current_sector = history_calc_sector_addr(leakage.history_metadata.write_index);
uint32_t prev_sector = history_calc_sector_addr(
(leakage.history_metadata.write_index == 0) ?
leakage.history_metadata.max_records - 1 :
leakage.history_metadata.write_index - 1);
/* 如果切换到新扇区,需要擦除 */
if(current_sector != prev_sector)
{
w25q32_sector_erase(current_sector);
}
/* 写入记录 */
w25q32.write(write_addr, (uint8_t*)&new_alarm, HISTORY_ALARM_RECORD_SIZE);
/* 更新元数据 */
leakage.history_metadata.write_index++;
if(leakage.history_metadata.write_index >= leakage.history_metadata.max_records)
{
leakage.history_metadata.write_index = 0;
}
if(leakage.history_metadata.total_records < leakage.history_metadata.max_records)
{
leakage.history_metadata.total_records++;
}
/* 保存元数据 */
history_save_metadata();
}
/* 读取历史报警记录 */
static u8 history_read_record(u32 record_index, app_leakage_history_alarm_t *record)
{
if(record_index >= leakage.history_metadata.total_records)
{
return 0; /* 记录索引无效 */
}
/* 计算实际存储索引(考虑循环队列) */
uint32_t actual_index;
if(leakage.history_metadata.total_records == leakage.history_metadata.max_records)
{
/* 缓冲区已满,计算相对索引 */
actual_index = (leakage.history_metadata.write_index + record_index) %
leakage.history_metadata.max_records;
}
else
{
/* 缓冲区未满,直接读取 */
actual_index = record_index;
}
uint32_t read_addr = history_calc_record_addr(actual_index);
w25q32.read(read_addr, (uint8_t*)record, HISTORY_ALARM_RECORD_SIZE);
return 1;
}
/* 清空所有历史报警记录 */
static void history_clear_all(void)
{
/* 重置元数据 */
memset(&leakage.history_metadata, 0, sizeof(app_leakage_history_metadata_t));
leakage.history_metadata.max_records = MAX_HISTORY_ALARM_RECORDS;
/* 保存元数据 */
history_save_metadata();
/* 擦除所有数据扇区(可选) */
for(uint32_t i = 0; i < HISTORY_ALARM_SECTORS_NEEDED; i++)
{
uint32_t sector_addr = W25Q32_HISTORY_ALARM_DATA_ADDR + i * W25Q32_SECTOR_SIZE;
w25q32_sector_erase(sector_addr);
}
}
/* 初始化历史报警模块 */
static void history_init(void)
{
/* 读取元数据 */
history_read_metadata();
}
+100
View File
@@ -0,0 +1,100 @@
#ifndef _APP_LEAKAGE_H_
#define _APP_LEAKAGE_H_
#include "main.h"
#define ENABLE (1)
#define DISABLE (0)
#define APP_LEAKAGE_SUB_DEVICE_STATE_LEAKAGE (0x0001) /*漏液状态*/
#define APP_LEAKAGE_SUB_DEVICE_STATE_OPEN (0x0002) /*断带状态*/
#define APP_LEAKAGE_SUB_DEVICE_STATE_TIME_OUT (0xf000) /*通讯超时*/
#define APP_LEAKAGE_STRING_NANE_LEN (10)
#define APP_LEAKAGE_SUB_DEVICE_NUM (32)
#define APP_LEAKAGE_SUB_DEVICE_CH_NUM (4)
void app_leakage_task(void);
void app_leakage_region_classify(void);
void history_add_alarm_record(u8 region_idx, u8 device_idx, u8 channel, u16 alarm_type, u16 leak_distance);
/*子设备存储的参数*/
typedef struct
{
u8 state; /*状态 使能 非使能*/
u8 com; /*端口*/
u8 modbus_id; /*modbus id*/
u8 device_name[APP_LEAKAGE_STRING_NANE_LEN]; /*设备名*/
u8 region_name[APP_LEAKAGE_STRING_NANE_LEN]; /*区域名*/
}app_leakage_sub_device_flash_data_t;
/*子设备信息*/
typedef struct
{
app_leakage_sub_device_flash_data_t flash_data; /*flash存储数据*/
struct
{
u16 state; /*状态*/
u16 distance; /*漏液距离*/
}ch_data[APP_LEAKAGE_SUB_DEVICE_CH_NUM]; /*通道数据*/
u8 heartbeat; /*心跳包,0-59循环*/
u8 test_mode; /*测试模式,0=正常,1-4=测试对应通道*/
}app_leakage_sub_device_class_t;
/*区域信息*/
typedef struct
{
u8 leakage_num; /*漏液数量*/
u8 open_num; /*断带数量*/
u8 time_out_num; /*通讯超时数量*/
u8 sub_device_num; /*设备总数量*/
u8 name[APP_LEAKAGE_STRING_NANE_LEN]; /*区域名称*/
u8 sub_device_index[APP_LEAKAGE_SUB_DEVICE_NUM]; /*设备的索引*/
}app_leakage_region_data_class_t;
/* 历史报警记录结构 */
typedef struct
{
u8 region_name[APP_LEAKAGE_STRING_NANE_LEN]; /* 区域名 */
u8 device_id; /* 设备ID */
u8 device_name[APP_LEAKAGE_STRING_NANE_LEN]; /* 设备名称 */
u16 alarm_type; /* 报警类型 */
u8 start_time[6]; /* 开始时间: 年(2字节)月日时分 */
u16 leak_distance; /* 漏液距离 (0表示非漏液报警) */
u8 channel; /* 通道号 (0-3) */
} app_leakage_history_alarm_t;
/* 历史报警管理结构 */
typedef struct
{
u32 total_records; /* 总记录数 */
u32 write_index; /* 写指针 */
u32 read_index; /* 读指针 */
u32 max_records; /* 最大记录数 */
} app_leakage_history_metadata_t;
typedef struct
{
u8 region_num;
u8 sub_device_num;
app_leakage_region_data_class_t region_data[APP_LEAKAGE_SUB_DEVICE_NUM];
app_leakage_sub_device_class_t sub_device_data[APP_LEAKAGE_SUB_DEVICE_NUM];
app_leakage_history_metadata_t history_metadata;
void (*init)(void); /*初始化*/
void (*task)(void); /*执行任务*/
}app_leakage_t;
typedef struct
{
u8 (*read_history)(u32, app_leakage_history_alarm_t *);
void (*clean_history)(void);
void (*init_history)(void);
}app_hitory_t;
extern app_leakage_t leakage;
extern app_hitory_t history;
#endif
+195
View File
@@ -0,0 +1,195 @@
#include "app_timer.h"
#include "app.h"
/* 函数声明 */
static void app_timer_task(void);
static void app_timer_init(u8 task_num, app_timer_class_t *p_timer_class);
static void app_timer_task_increment_int(u16 ms_tick);
/******************************************
* 结构体: app_timer
* 功能: 应用定时器实例
* 描述: 定时器控制结构体的具体实例
*******************************************/
app_timer_t app_timer =
{
.p_timer_class = NULL,
.init = app_timer_init,
.task = app_timer_task,
.increment_int = app_timer_task_increment_int,
};
/* 全局指针,指向定时器结构体 */
app_timer_t *p_app_timer = &app_timer;
/******************************************
* 函数: app_timer_init
* 功能: 定时器初始化
* 参数: task_num - 任务数量
* p_timer_class - 任务时间片数组指针
* 返回: 无
* 描述: 初始化定时器,设置任务数量和任务数组
*******************************************/
static void app_timer_init(u8 task_num, app_timer_class_t *p_timer_class)
{
p_app_timer->task_num = task_num;
p_app_timer->p_timer_class = p_timer_class;
}
/******************************************
* 函数: app_timer_task
* 功能: 定时器任务调度
* 参数: 无
* 返回: 无
* 描述: 执行所有已到时间的任务
*******************************************/
static void app_timer_task(void)
{
u16 i;
/* 检查任务数组是否有效 */
if(NULL == p_app_timer->p_timer_class)
{
return;
}
/* 遍历所有任务 */
for (i = 0; i < p_app_timer->task_num; i++)
{
/* 检查任务是否需要执行 */
if (p_app_timer->p_timer_class[i].run_flag)
{
p_app_timer->p_timer_class[i].run_flag = 0; /* 清除执行标志 */
/* 检查任务函数是否有效 */
if (p_app_timer->p_timer_class[i].task == NULL)
{
continue;
}
/* 执行任务函数 */
p_app_timer->p_timer_class[i].task();
}
}
}
/******************************************
* 函数: app_timer_task_increment_int
* 功能: 中断递增函数
* 参数: ms_tick - 毫秒增量
* 返回: 无
* 描述: 在中断中调用,更新定时器计数器和检查任务时间片
*******************************************/
static void app_timer_task_increment_int(u16 ms_tick)
{
u16 i;
/* 更新毫秒级计数器 */
p_app_timer->ms_tick++;
/* 更新秒级计数器 */
if(p_app_timer->ms_tick >= 1000)
{
p_app_timer->s_tick++;
}
/* 检查任务数组是否有效 */
if(NULL == p_app_timer->p_timer_class)
{
return;
}
/* 更新所有任务的时间片计数器 */
for (i = 0; i < p_app_timer->task_num; i++)
{
/* 检查任务计数器是否有效 */
if (p_app_timer->p_timer_class[i].timer_count)
{
p_app_timer->p_timer_class[i].timer_count--;
/* 检查是否到达任务执行时间 */
if (p_app_timer->p_timer_class[i].timer_count == 0)
{
p_app_timer->p_timer_class[i].run_flag = 1;
p_app_timer->p_timer_class[i].timer_count = p_app_timer->p_timer_class[i].timer_reload;
}
}
}
}
/******************************************
* 函数: app_timer_check_time_out
* 功能: 检查超时
* 参数: time_start - 计时开始时间
* time_now - 当前时间
* time_out - 超时时间
* 返回: TIME_TRUE - 已超时,TIME_FALSE - 未超时
* 描述: 检查从time_start开始经过time_out时间后是否超时,
* 考虑了计数器溢出的情况
*******************************************/
u8 app_timer_check_time_out(u16 time_start, u16 time_now, u16 time_out)
{
u16 timer_activate_val;
/* 计算触发时间 */
timer_activate_val = time_out + time_start;
/* 考虑计数器溢出情况 */
if (timer_activate_val > time_start)
{
/* 未发生溢出 */
if ((time_now >= timer_activate_val) || (time_now < time_start))
{
return TIME_TRUE;
}
}
else if ((time_now >= timer_activate_val) && (time_now < time_start))
{
/* 发生溢出且当前时间在溢出后 */
return TIME_TRUE;
}
return TIME_FALSE;
}
/******************************************
* 函数: app_timer_check_run_time
* 功能: 计算剩余运行时间
* 参数: time_start - 计时开始时间
* time_now - 当前时间
* time_out - 超时时间
* 返回: 剩余时间(毫秒)
* 描述: 配合app_timer_check_time_out函数使用,
* 计算距离超时还有多少时间,考虑了计数器溢出
*******************************************/
u16 app_timer_check_run_time(u16 time_start, u16 time_now, u16 time_out)
{
u16 timer_activate_val;
/* 计算触发时间 */
timer_activate_val = time_out + time_start;
/* 考虑计数器溢出情况 */
if (timer_activate_val > time_start)
{
/* 未发生溢出,直接计算剩余时间 */
return (timer_activate_val - time_now);
}
else
{
/* 发生溢出,计算溢出后的剩余时间 */
return (65535U - time_now + timer_activate_val);
}
}
/******************************************
* 函数: delay_ms
* 功能: 阻塞式延时
* 参数: delay - 延时时间(毫秒)
* 返回: 无
* 描述: 使用HAL库提供的延时函数实现阻塞式延时
*******************************************/
void delay_ms(u16 delay)
{
HAL_Delay(delay);
}
+48
View File
@@ -0,0 +1,48 @@
#ifndef _APP_TIMER_H_
#define _APP_TIMER_H_
#include "main.h"
/* 时间相关宏定义 */
#define TIME_TRUE 1U /* 时间已到 */
#define TIME_FALSE 0U /* 时间未到 */
/******************************************
* 结构体: app_timer_class_t
* 功能: 任务时间片结构体
* 描述: 定义单个任务的时间片调度参数
*******************************************/
typedef struct
{
u8 run_flag; /* 调度标志,1:调度,0:挂起 */
u16 timer_count; /* 时间片计数值 */
u16 timer_reload; /* 时间片重载值 */
void (*task)(void); /* 任务函数指针 */
} app_timer_class_t;
/******************************************
* 结构体: app_timer_t
* 功能: 应用定时器结构体
* 描述: 管理所有任务的定时调度
*******************************************/
typedef struct
{
u16 ms_tick; /* 滴答毫秒级计数器 */
u16 s_tick; /* 滴答秒级计数器 */
u16 task_num; /* 任务数量 */
app_timer_class_t *p_timer_class; /* 任务时间片数组指针 */
void (*init)(u8, app_timer_class_t *); /* 初始化函数指针 */
void (*task)(void); /* 定时器任务函数指针 */
void (*increment_int)(u16); /* 中断递增函数指针 */
} app_timer_t;
/* 函数声明 */
u8 app_timer_check_time_out(u16 time_start, u16 time_now, u16 time_out);
u16 app_timer_check_run_time(u16 time_start, u16 time_now, u16 time_out);
void delay_ms(u16 delay);
/* 声明外部变量 */
extern app_timer_t app_timer;
#endif
+4
View File
@@ -0,0 +1,4 @@
#include "gas_data.h"
gas_data_t gas_data[SENSOR_NUM];
+38
View File
@@ -0,0 +1,38 @@
#ifndef _GAS_DATA_H__
#define _GAS_DATA_H__
#include "main.h"
#define SENSOR_NUM 16
typedef struct
{
u8 ver[20]; /*软件版本号*/
u8 sn[20]; /*SN号*/
u16 range; /*量程*/
s16 value; /*浓度*/
u16 pp_ad; /*峰峰值*/
u16 r_pp_ad; /*原始峰峰值*/
u16 pp_pix; /*峰峰值坐标*/
u16 light_ad; /*光功率*/
u16 tec_set_value; /*tec设定值*/
u16 tec_temp; /*tec温度*/
s16 temp; /*环境温度*/
u16 light_ad_max; /*波形最大值*/
u16 light_ad_min; /*波形最小值*/
u16 state_code; /*状态码*/
u16 dc_offset; /*直流偏置*/
//u16 ad_befor_multiple; /*AD前放大倍数*/
u16 demod_multiple; /*锁相放大倍数*/
//u16 mode; /*模式状态*/
s16 calib_temp; /*标定时的温度*/
u16 calib_press; /*标定时的压力*/
u16 calib_humidity; /*标定时的湿度*/
u16 fac_calib_code_h;
u16 fac_calib_code_l; /*厂家标定时的状态码*/
u16 reserve[1]; /*预留*/
}gas_data_t;
extern gas_data_t gas_data[SENSOR_NUM];
#endif
+12
View File
@@ -0,0 +1,12 @@
#ifndef _USR_CONFIG_H_
#define _USR_CONFIG_H_
#define USR_TRUE (1U)
#define USR_FALSE (0U)
#define USR_ENABLE (1U)
#define USR_DISABLE (0U)
#define USR_ON (1U)
#define USR_OFF (0U)
#endif
+112
View File
@@ -0,0 +1,112 @@
#include "bsp_74HC4067.h"
/*两片74HC4067,一片TX 一片RX 每片16通道*/
#define BSP_74HC4067_CH_MAX 16
/*TX*/
#define TX_EN_ENABLE HAL_GPIO_WritePin (TX_EN_GPIO_Port, TX_EN_Pin, GPIO_PIN_RESET)
#define TX_EN_DISENABLE HAL_GPIO_WritePin (TX_EN_GPIO_Port, TX_EN_Pin, GPIO_PIN_SET)
/*RX*/
#define RX_EN_ENABLE HAL_GPIO_WritePin (RX_EN_GPIO_Port, RX_EN_Pin, GPIO_PIN_RESET)
#define RX_EN_DISENABLE HAL_GPIO_WritePin (RX_EN_GPIO_Port, RX_EN_Pin, GPIO_PIN_SET)
/*LED通道指示*/
#define LED_CH0_ON HAL_GPIO_WritePin (RX_S3_GPIO_Port, RX_S3_Pin, GPIO_PIN_RESET)
#define LED_CH0_OFF HAL_GPIO_WritePin (RX_S3_GPIO_Port, RX_S3_Pin, GPIO_PIN_SET)
#define BSP_LOW GPIO_PIN_RESET
#define BSP_HIG GPIO_PIN_SET
#define BSP_LED_ON GPIO_PIN_RESET
#define BSP_LED_OFF GPIO_PIN_SET
//static GPIO_TypeDef* bsp_74HC4067_TX_SW_GPIO[4] = {TX_S0_GPIO_Port,TX_S1_GPIO_Port,TX_S2_GPIO_Port,TX_S3_GPIO_Port};
//static uint16_t bsp_74HC4067_TX_SW_Pin[4] = {TX_S0_Pin, TX_S1_Pin, TX_S2_Pin, TX_S3_Pin};
//static GPIO_TypeDef* bsp_74HC4067_RX_SW_GPIO[4] = {RX_S0_GPIO_Port,RX_S1_GPIO_Port,RX_S2_GPIO_Port,RX_S3_GPIO_Port};
//static uint16_t bsp_74HC4067_RX_SW_Pin[4] = {RX_S0_Pin, RX_S1_Pin, RX_S2_Pin, RX_S3_Pin};
//static GPIO_TypeDef* bsp_74HC4067_LED_CH_GPIO[BSP_74HC4067_CH_MAX] = {LED_CH1_GPIO_Port, LED_CH2_GPIO_Port, LED_CH3_GPIO_Port, LED_CH4_GPIO_Port, LED_CH5_GPIO_Port, LED_CH6_GPIO_Port, LED_CH7_GPIO_Port, LED_CH8_GPIO_Port, LED_CH9_GPIO_Port, LED_CH10_GPIO_Port, LED_CH11_GPIO_Port, LED_CH12_GPIO_Port, LED_CH13_GPIO_Port, LED_CH14_GPIO_Port, LED_CH15_GPIO_Port, LED_CH16_GPIO_Port};
//static uint16_t bsp_74HC4067_LED_CH_Pin[BSP_74HC4067_CH_MAX] = {LED_CH1_Pin, LED_CH2_Pin, LED_CH3_Pin, LED_CH4_Pin, LED_CH5_Pin, LED_CH6_Pin, LED_CH7_Pin, LED_CH8_Pin, LED_CH9_Pin, LED_CH10_Pin, LED_CH11_Pin, LED_CH12_Pin, LED_CH13_Pin, LED_CH14_Pin, LED_CH15_Pin, LED_CH16_Pin};
/*通道转换,硬件实际连接的通道与芯片定义通道不一致*/
static u8 bsp_74HC4067_TX_CH_Conv[BSP_74HC4067_CH_MAX] = {13,14,15,12,11,10,9, 8, 7, 4, 3, 2, 1, 0, 6, 5};
static u8 bsp_74HC4067_RX_CH_Conv[BSP_74HC4067_CH_MAX] = {13,14,15,8, 9, 10,11,12,0, 1, 2, 3, 4, 5, 6, 7};
static void bsp_74HC4067_Init(void);
static void bsp_74HC4067_Set_CH(u8 CH);
static u8 bsp_74HC4067_Get_CH(void);
static u8 bsp_74HC4067_CH;
bsp_74HC4067_t UartCH_Config =
{
.init = bsp_74HC4067_Init,
.ch_set = bsp_74HC4067_Set_CH,
.ch_get = bsp_74HC4067_Get_CH,
};
/*其他外设初始化后快速闪烁,提示初始化完成*/
static void bsp_74HC4067_Init(void)
{
bsp_74HC4067_CH = 0;
// TX_EN_ENABLE;
// RX_EN_ENABLE;
bsp_74HC4067_Set_CH(0);
}
//static u8 CH;
static void bsp_74HC4067_Set_CH(u8 CH1)
{
u8 CH = 0;
if(CH >= BSP_74HC4067_CH_MAX)
{
return ;
}
u8 i,TX_CH,RX_CH;
bsp_74HC4067_CH = CH;
TX_CH = bsp_74HC4067_TX_CH_Conv[CH];
RX_CH = bsp_74HC4067_RX_CH_Conv[CH];
/*选择对应的通道输出*/
for(i=0;i<4;i++)
{
if((TX_CH >> i) & 0x01)
{
// HAL_GPIO_WritePin(bsp_74HC4067_TX_SW_GPIO[i],bsp_74HC4067_TX_SW_Pin[i],BSP_HIG);
}
else
{
// HAL_GPIO_WritePin(bsp_74HC4067_TX_SW_GPIO[i],bsp_74HC4067_TX_SW_Pin[i],BSP_LOW);
}
if((RX_CH >> i) & 0x01)
{
// HAL_GPIO_WritePin(bsp_74HC4067_RX_SW_GPIO[i],bsp_74HC4067_RX_SW_Pin[i],BSP_HIG);
}
else
{
// HAL_GPIO_WritePin(bsp_74HC4067_RX_SW_GPIO[i],bsp_74HC4067_RX_SW_Pin[i],BSP_LOW);
}
}
/*开启对应指示灯*/
for(i=0;i<BSP_74HC4067_CH_MAX;i++)
{
if(i == CH)
{
// HAL_GPIO_WritePin(bsp_74HC4067_LED_CH_GPIO[i],bsp_74HC4067_LED_CH_Pin[i],BSP_LED_ON);
}
else
{
// HAL_GPIO_WritePin(bsp_74HC4067_LED_CH_GPIO[i],bsp_74HC4067_LED_CH_Pin[i],BSP_LED_OFF);
}
}
// HAL_Delay(20);
}
static u8 bsp_74HC4067_Get_CH(void)
{
return bsp_74HC4067_CH;
}
+15
View File
@@ -0,0 +1,15 @@
#ifndef _BSP_74HC4067_H_
#define _BSP_74HC4067_H_
#include "main.h"
typedef struct
{
void (*init)(void);
void (*ch_set)(u8);
u8 (*ch_get)(void);
}bsp_74HC4067_t;
extern bsp_74HC4067_t UartCH_Config;
#endif
+247
View File
@@ -0,0 +1,247 @@
#include "bsp_DS1302.h"
#define bsp_DS1302_DELAY() do{ \
__NOP();__NOP();__NOP();__NOP();\
__NOP();__NOP();__NOP();__NOP();\
__NOP();__NOP();__NOP();__NOP();\
__NOP();__NOP();__NOP();__NOP();\
__NOP();__NOP();__NOP();__NOP();\
__NOP();__NOP();__NOP();__NOP();\
__NOP();__NOP();__NOP();__NOP();\
}while(0)
#define RST_CLR HAL_GPIO_WritePin(DS1302_RST_GPIO_Port, DS1302_RST_Pin, GPIO_PIN_RESET )
#define RST_SET HAL_GPIO_WritePin(DS1302_RST_GPIO_Port, DS1302_RST_Pin, GPIO_PIN_SET )
#define IO_CLR HAL_GPIO_WritePin(DS1302_DIO_GPIO_Port, DS1302_DIO_Pin, GPIO_PIN_RESET )
#define IO_SET HAL_GPIO_WritePin(DS1302_DIO_GPIO_Port, DS1302_DIO_Pin, GPIO_PIN_SET )
#define IO_READ HAL_GPIO_ReadPin (DS1302_DIO_GPIO_Port, DS1302_DIO_Pin )
#define SCK_CLR HAL_GPIO_WritePin(DS1302_CLK_GPIO_Port, DS1302_CLK_Pin, GPIO_PIN_RESET )
#define SCK_SET HAL_GPIO_WritePin(DS1302_CLK_GPIO_Port, DS1302_CLK_Pin, GPIO_PIN_SET )
static void bsp_DS1302Init(void);
static void bsp_DS1302_Task(void);
static u8 bsp_DS1302_Set(bsp_DS1302_Time_t *pTime);
bsp_DS1302_t DS1302 =
{
.Init = bsp_DS1302Init,
.Task = bsp_DS1302_Task,
.Set = bsp_DS1302_Set,
};
bsp_DS1302_t *pDS1302 = &DS1302;
static void bsp_DS1302DataInput(void)
{
GPIO_InitTypeDef GPIO_InitStruct; //定义GPIO结构体
GPIO_InitStruct.Pin = DS1302_DIO_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(DS1302_DIO_GPIO_Port, &GPIO_InitStruct);
}
static void bsp_DS1302DataOutput(void)
{
GPIO_InitTypeDef GPIO_InitStruct; //定义GPIO结构体
GPIO_InitStruct.Pin = DS1302_DIO_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(DS1302_DIO_GPIO_Port, &GPIO_InitStruct);
}
/*向bsp_DS1302写入一字节数据*/
static void bsp_DS1302_write_byte(u8 Addr, u8 Data)
{
u8 i;
RST_SET; /*启动bsp_DS1302总线*/
bsp_DS1302_DELAY();
/*写入目标地址:addr*/
Addr = Addr & 0xFE;/*最低位置零*/
for (i = 0; i < 8; i++)
{
if (Addr & 0x01)
{
IO_SET;
}
else
{
IO_CLR;
}
bsp_DS1302_DELAY();
SCK_SET;
bsp_DS1302_DELAY();
SCK_CLR;
bsp_DS1302_DELAY();
Addr = Addr >> 1;
}
/*写入数据:d*/
for (i = 0; i < 8; i++)
{
if (Data & 0x01)
{
IO_SET;
}
else
{
IO_CLR;
}
bsp_DS1302_DELAY();
SCK_SET;
bsp_DS1302_DELAY();
SCK_CLR;
bsp_DS1302_DELAY();
Data = Data >> 1;
}
RST_CLR; /*停止bsp_DS1302总线*/
bsp_DS1302_DELAY();
}
/*从bsp_DS1302读出一字节数据*/
static u8 bsp_DS1302_read_byte(u8 Addr)
{
u8 i;
u8 temp;
RST_SET; /*启动bsp_DS1302总线*/
bsp_DS1302_DELAY();
/*写入目标地址:addr*/
Addr = Addr | 0x01;/*最低位置高*/
for (i = 0; i < 8; i++)
{
if (Addr & 0x01)
{
IO_SET;
}
else
{
IO_CLR;
}
bsp_DS1302_DELAY();
SCK_SET;
bsp_DS1302_DELAY();
SCK_CLR;
bsp_DS1302_DELAY();
Addr = Addr >> 1;
}
bsp_DS1302DataInput();
/*输出数据:temp*/
for (i = 0; i < 8; i++)
{
temp = temp >> 1;
if (IO_READ)
{
temp |= 0x80;
}
else
{
temp &= 0x7F;
}
bsp_DS1302_DELAY();
SCK_SET;
bsp_DS1302_DELAY();
SCK_CLR;
bsp_DS1302_DELAY();
}
RST_CLR; /*停止bsp_DS1302总线*/
bsp_DS1302_DELAY();
bsp_DS1302DataOutput();
return temp;
}
static u8 HexToBCD(u8 code)
{
u8 temp;
temp = ((code / 10) << 4) + (code % 10);
return temp;
}
static u8 bsp_DS1302_Set(bsp_DS1302_Time_t *pTime)
{
if ((pDS1302->Time.Year > 99) || (pDS1302->Time.Month > 12) || (pDS1302->Time.Day > 31) ||
(pDS1302->Time.Hour > 23) || (pDS1302->Time.Minute > 59) || (pDS1302->Time.Second > 59))
{
return USR_FALSE;
}
else
{
bsp_DS1302_write_byte(BSP_DS1302_CONTROL_ADDR, 0x00); //关闭写保护
bsp_DS1302_write_byte(BSP_DS1302_SEC_ADDR, 0x80); //暂停
bsp_DS1302_write_byte(BSP_DS1302_YEAR_ADDR, HexToBCD(pTime->Year));
bsp_DS1302_write_byte(BSP_DS1302_MONTH_ADDR, HexToBCD(pTime->Month));
bsp_DS1302_write_byte(BSP_DS1302_DATA_ADDR, HexToBCD(pTime->Day));
bsp_DS1302_write_byte(BSP_DS1302_HOUR_ADDR, HexToBCD(pTime->Hour));
bsp_DS1302_write_byte(BSP_DS1302_MIN_ADDR, HexToBCD(pTime->Minute));
bsp_DS1302_write_byte(BSP_DS1302_SEC_ADDR, HexToBCD(pTime->Second));
bsp_DS1302_write_byte(BSP_DS1302_CONTROL_ADDR, 0x80); //打开写保护
return USR_TRUE;
}
}
static void bsp_DS1302_Task(void)
{
u8 RegData;
RegData = bsp_DS1302_read_byte(BSP_DS1302_YEAR_ADDR);
pDS1302->Time.Year = (RegData / 16) * 10 + RegData % 16;
RegData = bsp_DS1302_read_byte(BSP_DS1302_MONTH_ADDR);
pDS1302->Time.Month = (RegData / 16) * 10 + RegData % 16;
RegData = bsp_DS1302_read_byte(BSP_DS1302_DATA_ADDR);
pDS1302->Time.Day = (RegData / 16) * 10 + RegData % 16;
RegData = bsp_DS1302_read_byte(BSP_DS1302_HOUR_ADDR);
pDS1302->Time.Hour = (RegData / 16) * 10 + RegData % 16;
RegData = bsp_DS1302_read_byte(BSP_DS1302_MIN_ADDR);
pDS1302->Time.Minute = (RegData / 16) * 10 + RegData % 16;
RegData = bsp_DS1302_read_byte(BSP_DS1302_SEC_ADDR);
pDS1302->Time.Second = (RegData / 16) * 10 + RegData % 16;
}
static void bsp_DS1302Init(void)
{
RST_SET;
SCK_CLR;
bsp_DS1302_Task();
if ((pDS1302->Time.Year > 99) || (pDS1302->Time.Month > 12) || (pDS1302->Time.Day > 31) ||
(pDS1302->Time.Hour > 23) || (pDS1302->Time.Minute > 59) || (pDS1302->Time.Second > 59))
{
pDS1302->Time.Year = 26;
pDS1302->Time.Month = 1;
pDS1302->Time.Day = 1;
pDS1302->Time.Hour = 0;
pDS1302->Time.Minute = 0;
pDS1302->Time.Second = 0;
bsp_DS1302_Set(&pDS1302->Time);
}
}
+206
View File
@@ -0,0 +1,206 @@
#include "bsp_DS1302.h"
#define bsp_DS1302_DELAY() do{ \
__NOP();__NOP();__NOP();__NOP();\
__NOP();__NOP();__NOP();__NOP();\
__NOP();__NOP();__NOP();__NOP();\
__NOP();__NOP();__NOP();__NOP();\
__NOP();__NOP();__NOP();__NOP();\
}while(0)
#define RST_CLR HAL_GPIO_WritePin(DS1302_RST_GPIO_Port, DS1302_RST_Pin, GPIO_PIN_RESET )
#define RST_SET HAL_GPIO_WritePin(DS1302_RST_GPIO_Port, DS1302_RST_Pin, GPIO_PIN_SET )
#define IO_CLR HAL_GPIO_WritePin(DS1302_DIO_GPIO_Port, DS1302_DIO_Pin, GPIO_PIN_RESET )
#define IO_SET HAL_GPIO_WritePin(DS1302_DIO_GPIO_Port, DS1302_DIO_Pin, GPIO_PIN_SET )
#define IO_READ HAL_GPIO_ReadPin (DS1302_DIO_GPIO_Port, DS1302_DIO_Pin )
#define SCK_CLR HAL_GPIO_WritePin(DS1302_CLK_GPIO_Port, DS1302_CLK_Pin, GPIO_PIN_RESET )
#define SCK_SET HAL_GPIO_WritePin(DS1302_CLK_GPIO_Port, DS1302_CLK_Pin, GPIO_PIN_SET )
static void bsp_DS1302Init(void);
static void bsp_DS1302_Task(void);
static void bsp_DS1302_Set(bsp_DS1302_Time_t *pTime);
bsp_DS1302_t DS1302 =
{
.Init = bsp_DS1302Init,
.Task = bsp_DS1302_Task,
.Set = bsp_DS1302_Set,
};
bsp_DS1302_t *pDS1302 = &DS1302;
static void bsp_DS1302DataInput(void)
{
GPIO_InitTypeDef GPIO_InitStruct; //定义GPIO结构体
GPIO_InitStruct.Pin = DS1302_DIO_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(DS1302_DIO_GPIO_Port, &GPIO_InitStruct);
}
static void bsp_DS1302DataOutput(void)
{
GPIO_InitTypeDef GPIO_InitStruct; //定义GPIO结构体
GPIO_InitStruct.Pin = DS1302_DIO_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(DS1302_DIO_GPIO_Port, &GPIO_InitStruct);
}
/*向bsp_DS1302写入一字节数据*/
static void bsp_DS1302_write_byte(u8 Addr, u8 Data)
{
u8 i;
RST_SET; /*启动bsp_DS1302总线*/
bsp_DS1302_DELAY();
/*写入目标地址:addr*/
Addr = Addr & 0xFE;/*最低位置零*/
for(i=0; i<8; i++){
if(Addr&0x01) IO_SET;
else IO_CLR;
bsp_DS1302_DELAY();
SCK_SET;
bsp_DS1302_DELAY();
SCK_CLR;
bsp_DS1302_DELAY();
Addr = Addr >> 1;
}
/*写入数据:d*/
for(i=0; i<8; i++){
if(Data&0x01) IO_SET;
else IO_CLR;
bsp_DS1302_DELAY();
SCK_SET;
bsp_DS1302_DELAY();
SCK_CLR;
bsp_DS1302_DELAY();
Data = Data >> 1;
}
RST_CLR; /*停止bsp_DS1302总线*/
bsp_DS1302_DELAY();
}
/*从bsp_DS1302读出一字节数据*/
static u8 bsp_DS1302_read_byte(u8 Addr)
{
u8 i;
u8 temp;
RST_SET; /*启动bsp_DS1302总线*/
bsp_DS1302_DELAY();
/*写入目标地址:addr*/
Addr = Addr | 0x01;/*最低位置高*/
for(i=0; i<8; i++)
{
if(Addr&0x01)
{
IO_SET;
}
else
{
IO_CLR;
}
bsp_DS1302_DELAY();
SCK_SET;
bsp_DS1302_DELAY();
SCK_CLR;
bsp_DS1302_DELAY();
Addr = Addr >> 1;
}
bsp_DS1302DataInput();
/*输出数据:temp*/
for(i=0; i<8; i++)
{
temp = temp>>1;
if(IO_READ) temp |= 0x80;
else temp&=0x7F;
bsp_DS1302_DELAY();
SCK_SET;
bsp_DS1302_DELAY();
SCK_CLR;
bsp_DS1302_DELAY();
}
RST_CLR; /*停止bsp_DS1302总线*/
bsp_DS1302_DELAY();
bsp_DS1302DataOutput();
return temp;
}
static u8 HexToBCD(u8 code)
{
u8 temp;
temp = ((code / 10)<<4)+(code % 10);
return temp;
}
static void bsp_DS1302_Set(bsp_DS1302_Time_t *pTime)
{
bsp_DS1302_write_byte(BSP_DS1302_CONTROL_ADDR,0x00); //关闭写保护
bsp_DS1302_write_byte(BSP_DS1302_SEC_ADDR,0x80); //暂停
bsp_DS1302_write_byte(BSP_DS1302_YEAR_ADDR, HexToBCD(pTime->Year));
bsp_DS1302_write_byte(BSP_DS1302_MONTH_ADDR, HexToBCD(pTime->Month));
bsp_DS1302_write_byte(BSP_DS1302_DATA_ADDR, HexToBCD(pTime->Day));
bsp_DS1302_write_byte(BSP_DS1302_HOUR_ADDR, HexToBCD(pTime->Hour));
bsp_DS1302_write_byte(BSP_DS1302_MIN_ADDR, HexToBCD(pTime->Minute));
bsp_DS1302_write_byte(BSP_DS1302_SEC_ADDR, HexToBCD(pTime->Second));
bsp_DS1302_write_byte(BSP_DS1302_CONTROL_ADDR,0x80); //打开写保护
}
static void bsp_DS1302_Task(void)
{
u8 RegData;
RegData = bsp_DS1302_read_byte(BSP_DS1302_YEAR_ADDR);
pDS1302->Time.Year = (RegData/16)*10 + RegData%16;
RegData = bsp_DS1302_read_byte(BSP_DS1302_MONTH_ADDR);
pDS1302->Time.Month = (RegData/16)*10 + RegData%16;
RegData = bsp_DS1302_read_byte(BSP_DS1302_DATA_ADDR);
pDS1302->Time.Day = (RegData/16)*10 + RegData%16;
RegData = bsp_DS1302_read_byte(BSP_DS1302_HOUR_ADDR);
pDS1302->Time.Hour = (RegData/16)*10 + RegData%16;
RegData = bsp_DS1302_read_byte(BSP_DS1302_MIN_ADDR);
pDS1302->Time.Minute = (RegData/16)*10 + RegData%16;
RegData = bsp_DS1302_read_byte(BSP_DS1302_SEC_ADDR);
pDS1302->Time.Second = (RegData/16)*10 + RegData%16;
}
static void bsp_DS1302Init(void)
{
RST_SET;
SCK_CLR;
bsp_DS1302_Task();
if((pDS1302->Time.Year>99)||(pDS1302->Time.Month>12)||(pDS1302->Time.Day>31)||
(pDS1302->Time.Hour>23)||(pDS1302->Time.Minute>59)||(pDS1302->Time.Second>59))
{
pDS1302->Time.Year = 25;
pDS1302->Time.Month = 1;
pDS1302->Time.Day = 1;
pDS1302->Time.Hour = 0;
pDS1302->Time.Minute = 0;
pDS1302->Time.Second = 0;
bsp_DS1302_Set(&pDS1302->Time);
}
}
+38
View File
@@ -0,0 +1,38 @@
#ifndef __BSP_DS1302_H__
#define __BSP_DS1302_H__
#include "main.h"
#include "usr_config.h"
#define BSP_DS1302_SEC_ADDR 0x80 //秒数据地址
#define BSP_DS1302_MIN_ADDR 0x82 //分数据地址
#define BSP_DS1302_HOUR_ADDR 0x84 //时数据地址
#define BSP_DS1302_DATA_ADDR 0x86 //日数据地址
#define BSP_DS1302_MONTH_ADDR 0x88 //月数据地址
#define BSP_DS1302_DAY_ADDR 0x8a //星期数据地址
#define BSP_DS1302_YEAR_ADDR 0x8c //年数据地址
#define BSP_DS1302_CONTROL_ADDR 0x8e //控制数据地址
#define BSP_DS1302_CHARGER_ADDR 0x90
#define BSP_DS1302_CLKBURST_ADDR 0xbe
typedef struct
{
u16 Year;
u8 Month;
u8 Day;
u8 Hour;
u8 Minute;
u8 Second;
}bsp_DS1302_Time_t;
typedef struct
{
bsp_DS1302_Time_t Time;
void (*Init)(void);
u8 (*Set)(bsp_DS1302_Time_t *);
void (*Task)(void);
}bsp_DS1302_t;
extern bsp_DS1302_t DS1302;//系统时间
#endif
+1
View File
@@ -0,0 +1 @@
#include "bsp_Delay.h"
+6
View File
@@ -0,0 +1,6 @@
#ifndef _BSP_DELAY_H_
#define _BSP_DELAY_H_
#include "main.h"
#endif
+186
View File
@@ -0,0 +1,186 @@
#include "bsp_Flash.h"
#include "string.h"
#include "bsp_Wdg.h"
#include "gas_data.h"
/* FLASH Memory Definitions */
//#define BSP_FLASH_SIZE (0x100000UL)
//#define BSP_FLASH_PAGE_SIZE (PAGESIZE)
//#define BSP_FLASH_PAGE_NUM (BSP_FLASH_SIZE/BSP_FLASH_PAGE_SIZE)
//#define BSP_FLASH_ADDR_RW(n) ((uint32_t)(FLASH_BASE + (BSP_FLASH_PAGE_NUM - (n)) * BSP_FLASH_PAGE_SIZE))
//#define BSP_FLASH_DATASAVE_ADDR BSP_FLASH_ADDR_RW(1)
//FLASH地址
#define BSP_FLASH_SECTION_0_ADDR ((u32)0x08000000) //16k
#define BSP_FLASH_SECTION_1_ADDR ((u32)0x08004000) //16k
#define BSP_FLASH_SECTION_2_ADDR ((u32)0x08008000) //16k
#define BSP_FLASH_SECTION_3_ADDR ((u32)0x0800C000) //16k
#define BSP_FLASH_SECTION_4_ADDR ((u32)0x08010000) //64k
#define BSP_FLASH_SECTION_5_ADDR ((u32)0x08020000) //128k
#define BSP_FLASH_SECTION_6_ADDR ((u32)0x08040000) //128k
#define BSP_FLASH_SECTION_7_ADDR ((u32)0x08060000) //128k
#define BSP_FLASH_SECTION_8_ADDR ((u32)0x08080000) //128k
#define BSP_FLASH_SECTION_9_ADDR ((u32)0x080A0000) //128k
#define BSP_FLASH_SECTION_10_ADDR ((u32)0x080C0000) //128k
#define BSP_FLASH_SECTION_11_ADDR ((u32)0x080E0000) //128k
#define BSP_FLASH_DATASAVE_ADDR BSP_FLASH_SECTION_11_ADDR//最后一片扇区 128k
static void bsp_Flash_Init(void);
static void bsp_FlashDataWrite(void);
static void bsp_FlashDataRead(void);
static void bsp_FlashReset(void);
bsp_Flash_t Usr_Flash =
{
.Init = bsp_Flash_Init,
.Write = bsp_FlashDataWrite,
.Read = bsp_FlashDataRead,
.Reset = bsp_FlashReset,
};
bsp_Flash_t *p_Usr_Flash = &Usr_Flash;
// 擦除指定页
static HAL_StatusTypeDef bsp_FLASH_ErasePage(uint32_t PageAddress)
{
//初始化FLASH_EraseInitTypeDef
FLASH_EraseInitTypeDef f;
f.TypeErase = FLASH_TYPEERASE_SECTORS;
f.Sector = FLASH_SECTOR_11;
f.NbSectors = 1;
f.VoltageRange = VOLTAGE_RANGE_3;
//设置PageError
uint32_t PageError = 0;
//调用擦除函数
return HAL_FLASHEx_Erase(&f, &PageError);
}
// 读取数据 - 按32位读取
static void bsp_Flash_STMFLASH_Read(uint32_t ReadAddr, void *pBuffer, uint32_t size)
{
uint8_t *pBuf = (uint8_t*)pBuffer;
uint32_t *addr = (uint32_t*)ReadAddr;
uint32_t words = size / 4;
uint32_t bytes_remaining = size % 4;
// 读取完整的32位字
for(uint32_t i = 0; i < words; i++)
{
*((uint32_t*)pBuf) = addr[i];
pBuf += 4;
}
// 读取剩余的字节
if(bytes_remaining > 0)
{
uint32_t last_word = addr[words];
uint8_t *last_bytes = (uint8_t*)&last_word;
for(uint32_t i = 0; i < bytes_remaining; i++)
{
pBuf[i] = last_bytes[i];
}
}
}
// 写入数据 - 按32位写入
static HAL_StatusTypeDef bsp_Flash_STMFLASH_Write(uint32_t WriteAddr, void *pBuffer, uint32_t size)
{
HAL_StatusTypeDef status = HAL_OK;
uint8_t *pBuf = (uint8_t*)pBuffer;
uint32_t words = size / 4;
uint32_t bytes_remaining = size % 4;
uint32_t current_addr = WriteAddr;
HAL_FLASH_Unlock();
// 擦除目标页
status = bsp_FLASH_ErasePage(WriteAddr);
if(status != HAL_OK)
{
HAL_FLASH_Lock();
return status;
}
// 写入完整的32位字
for(uint32_t i = 0; i < words; i++)
{
status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD,
current_addr,
*((uint32_t*)pBuf));
if(status != HAL_OK) break;
current_addr += 4;
pBuf += 4;
}
// 写入剩余的字节
if(status == HAL_OK && bytes_remaining > 0)
{
uint32_t last_word = 0xFFFFFFFF; // 默认填充0xFF
uint8_t *last_bytes = (uint8_t*)&last_word;
// 复制剩余数据
for(uint32_t i = 0; i < bytes_remaining; i++)
{
last_bytes[i] = pBuf[i];
}
status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, current_addr, last_word);
}
HAL_FLASH_Lock();
return status;
}
static void bsp_FlashReset(void)
{
bsp_FlashDataWrite();
}
static void bsp_Flash_Init(void)
{
bsp_FlashDataRead();
if(p_Usr_Flash->FlashData.modbus_read_reg_num > 1000)
p_Usr_Flash->FlashData.modbus_read_reg_num = sizeof(gas_data_t)/2;
if(p_Usr_Flash->FlashData.modbus_read_sensor_num > SENSOR_NUM)
p_Usr_Flash->FlashData.modbus_read_sensor_num = SENSOR_NUM;
memcpy(&Usr_Flash.TempFlashData, &Usr_Flash.FlashData, sizeof(bsp_FlashData_t));
}
static void bsp_FlashDataWrite(void)
{
/*防止重复擦写相同数据*/
if(memcmp(&Usr_Flash.TempFlashData, &Usr_Flash.FlashData, sizeof(bsp_FlashData_t)) != 0)
{
Wdg.Feed();
__disable_irq(); // 禁用全局中断
HAL_StatusTypeDef status = bsp_Flash_STMFLASH_Write(BSP_FLASH_DATASAVE_ADDR,&Usr_Flash.FlashData,sizeof(bsp_FlashData_t));
if(status == HAL_OK)
{
// 写入成功,更新临时数据
memcpy(&Usr_Flash.TempFlashData, &Usr_Flash.FlashData, sizeof(bsp_FlashData_t));
}
else
{
}
__enable_irq(); // 恢复中断
Wdg.Feed();
}
}
static void bsp_FlashDataRead(void)
{
Wdg.Feed();
bsp_Flash_STMFLASH_Read(BSP_FLASH_DATASAVE_ADDR,
&Usr_Flash.FlashData,
sizeof(bsp_FlashData_t));
Wdg.Feed();
}
+31
View File
@@ -0,0 +1,31 @@
#ifndef _BSP_FLASH_H_
#define _BSP_FLASH_H_
#include "main.h"
#include "stdio.h"
#include "string.h"
typedef struct
{
/*用于判断数据是否一致*/
u16 sn[5];
u8 modbus_id;
u16 modbus_read_reg_num;
u16 modbus_read_sensor_num;
} bsp_FlashData_t;
typedef struct
{
bsp_FlashData_t TempFlashData;
bsp_FlashData_t FlashData;
void (*Init)(void);
void (*Write)(void);
void (*Read)(void);
void (*Reset)(void);
} bsp_Flash_t;
extern bsp_Flash_t Usr_Flash;
#endif
+31
View File
@@ -0,0 +1,31 @@
#include "bsp_Led.h"
#include "app_timer.h"
#define LED_ON HAL_GPIO_WritePin (LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET)
#define LED_OFF HAL_GPIO_WritePin (LED_GPIO_Port, LED_Pin, GPIO_PIN_SET)
#define LED_TOGGLE HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin)
static void bsp_led_init(void);
static void bsp_led_task(void);
bsp_led_t led =
{
.init = bsp_led_init,
.task = bsp_led_task,
};
/*其他外设初始化后快速闪烁,提示初始化完成*/
static void bsp_led_init(void)
{
for(u8 i = 0;i < 20;i++)
{
delay_ms(50);
HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
}
}
static void bsp_led_task(void)
{
HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
}
+15
View File
@@ -0,0 +1,15 @@
#ifndef _BSP_LED_H_
#define _BSP_LED_H_
#include "main.h"
typedef struct
{
void (*init)(void);
void (*task)(void);
}bsp_led_t;
extern bsp_led_t led;
#endif
+808
View File
@@ -0,0 +1,808 @@
/**********************************************************************************
* 文件名 W5500.c
* 描述 :W5500 驱动函数库
* 库版本 ST_v3.5
* 作者 :泥人通信模块开发团队
* 博客 http://nirenelec.blog.163.com
* 淘宝 http://nirenelec.taobao.com
**********************************************************************************/
//#include "stm32f1xx.h"
//#include "stm32f1xx_hal_spi.h"
#include "main.h"
#include "bsp_W5500.h"
#include "usart.h"
#include "stdio.h"
#include "spi.h"
//#include "bsp_print.h"
#define BSP_W5500_SPI_CS_LOW
/*Run_Mode 端口的运行模式*/
#define BSP_W5500_PORT_RUN_MODE_TCP_SERVER 0x00 /*TCP服务器模式*/
#define BSP_W5500_PORT_RUN_MODE_TCP_CLIENT 0x01 /*TCP客户端模式*/
#define BSP_W5500_PORT_RUN_MODE_UDP 0x02 /*UDP(广播)模式*/
/*Run_State 端口的运行状态 BIT位*/
#define BSP_W5500_PORT_RUN_STATE_INIT 0x01 /*端口完成初始化*/
#define BSP_W5500_PORT_RUN_STATE_CONN 0x02 /*端口完成连接,可以正常传输数据*/
/*TR_Data_State 端口的收发数据状态*/
#define BSP_W5500_PORT_DATA_RECEIVE 0x01 /*端口接收到一个数据包*/
#define BSP_W5500_PORT_DATA_TRANSMITOK 0x02 /*端口发送一个数据包完成*/
static void bsp_W5500_Interrupt_Process(void);
static void bsp_W5500_Init(void);
static void bsp_W5500_Task(void);
static void Write_SOCK_Data_Buffer(bsp_W5500_Class_t *pW5500_Class, u8 *dat_ptr, u16 size);
bsp_W5500_t W5500 =
{
.Gateway_IP = {192,168,1,1},
.Sub_Mask = {255,255,255,0},/*子网掩码*/
.Phy_Addr = {0x0c,0x29,0xab,0x7c,0x00,0x01},
//.IP_Addr = {169,254,107,101},
.IP_Addr = {192,168,100,101},
.Interrupt_Process = bsp_W5500_Interrupt_Process,
.Init = bsp_W5500_Init,
.Task = bsp_W5500_Task,
.Socket_Send = Write_SOCK_Data_Buffer,
.W5500_Class[0] =
{
.SocketPort = 0, /*使用端口0*/
.ConfigData.Gateway_IP = {192,168,1,1},
.ConfigData.Sub_Mask = {255,255,255,0},
.ConfigData.Phy_Addr = {0x0c,0x29,0xab,0x7c,0x00,0x01},
.ConfigData.IP_Addr = {192,168,100,101},
.ConfigData.Port = {0x13,0x88},
// .ConfigData.DIP = {192,168,1,32},
// .ConfigData.DPort = {0x03,0x09},
.Run_Mode = BSP_W5500_PORT_RUN_MODE_TCP_SERVER,
// .Rx_DataAnalysis = proto_HSMS_Rx_DataAnalysis,
},
};
bsp_W5500_t *pW5500 = &W5500;
/*******************************************************************************
* 函数名 : SPI1_Send_Byte
* 描述 : SPI1发送1个字节数据
* 输入 : dat:待发送的数据
* 输出 : 无
* 返回值 : 无
* 说明 : 无
*******************************************************************************/
void SPI1_Send_Byte(u8 dat)
{
// hspi1.Instance->DR=dat;
HAL_SPI_Transmit(&hspi1, &dat, 1, 0xff);
// while(__HAL_SPI_GET_FLAG(&hspi1,SPI_FLAG_TXE)==RESET);
// SPI_I2S_SendData(SPI1,dat);//写1个字节数据
// while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);//等待数据寄存器空
}
/*******************************************************************************
* 函数名 : SPI1_Send_Short
* 描述 : SPI1发送2个字节数据(16位)
* 输入 : dat:待发送的16位数据
* 输出 : 无
* 返回值 : 无
* 说明 : 无
*******************************************************************************/
void SPI1_Send_Short(u16 dat)
{
SPI1_Send_Byte(dat >> 8); // 写数据高位
SPI1_Send_Byte(dat); // 写数据低位
}
/*******************************************************************************
* 函数名 : Write_W5500_1Byte
* 描述 : 通过SPI1向指定地址寄存器写1个字节数据
* 输入 : reg:16位寄存器地址,dat:待写入的数据
* 输出 : 无
* 返回值 : 无
* 说明 : 无
*******************************************************************************/
void Write_W5500_1Byte(u16 reg, u8 dat)
{
HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_RESET); // 置W5500的SCS为低电平
SPI1_Send_Short(reg); // 通过SPI1写16位寄存器地址
SPI1_Send_Byte(FDM1 | RWB_WRITE | COMMON_R); // 通过SPI1写控制字节,1个字节数据长度,写数据,选择通用寄存器
SPI1_Send_Byte(dat); // 写1个字节数据
HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_SET); // 置W5500的SCS为高电平
}
/*******************************************************************************
* 函数名 : Write_W5500_2Byte
* 描述 : 通过SPI1向指定地址寄存器写2个字节数据
* 输入 : reg:16位寄存器地址,dat:16位待写入的数据(2个字节)
* 输出 : 无
* 返回值 : 无
* 说明 : 无
*******************************************************************************/
void Write_W5500_2Byte(u16 reg, u16 dat)
{
HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_RESET); // 置W5500的SCS为低电平
SPI1_Send_Short(reg); // 通过SPI1写16位寄存器地址
SPI1_Send_Byte(FDM2 | RWB_WRITE | COMMON_R); // 通过SPI1写控制字节,2个字节数据长度,写数据,选择通用寄存器
SPI1_Send_Short(dat); // 写16位数据
HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_SET); // 置W5500的SCS为高电平
}
/*******************************************************************************
* 函数名 : Write_W5500_nByte
* 描述 : 通过SPI1向指定地址寄存器写n个字节数据
* 输入 : reg:16位寄存器地址,*dat_ptr:待写入数据缓冲区指针,size:待写入的数据长度
* 输出 : 无
* 返回值 : 无
* 说明 : 无
*******************************************************************************/
void Write_W5500_nByte(u16 reg, u8 *dat_ptr, u16 size)
{
u16 i;
HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_RESET); // 置W5500的SCS为低电平
SPI1_Send_Short(reg); // 通过SPI1写16位寄存器地址
SPI1_Send_Byte(VDM | RWB_WRITE | COMMON_R); // 通过SPI1写控制字节,N个字节数据长度,写数据,选择通用寄存器
for (i = 0; i < size; i++) // 循环将缓冲区的size个字节数据写入W5500
{
SPI1_Send_Byte(*dat_ptr++); // 写一个字节数据
}
HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_SET); // 置W5500的SCS为高电平
}
/*******************************************************************************
* 函数名 : Write_W5500_SOCK_1Byte
* 描述 : 通过SPI1向指定端口寄存器写1个字节数据
* 输入 : s:端口号,reg:16位寄存器地址,dat:待写入的数据
* 输出 : 无
* 返回值 : 无
* 说明 : 无
*******************************************************************************/
void Write_W5500_SOCK_1Byte(SOCKET s, u16 reg, u8 dat)
{
HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_RESET); // 置W5500的SCS为低电平
SPI1_Send_Short(reg); // 通过SPI1写16位寄存器地址
SPI1_Send_Byte(FDM1 | RWB_WRITE | (s * 0x20 + 0x08)); // 通过SPI1写控制字节,1个字节数据长度,写数据,选择端口s的寄存器
SPI1_Send_Byte(dat); // 写1个字节数据
HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_SET); // 置W5500的SCS为高电平
}
/*******************************************************************************
* 函数名 : Write_W5500_SOCK_2Byte
* 描述 : 通过SPI1向指定端口寄存器写2个字节数据
* 输入 : s:端口号,reg:16位寄存器地址,dat:16位待写入的数据(2个字节)
* 输出 : 无
* 返回值 : 无
* 说明 : 无
*******************************************************************************/
void Write_W5500_SOCK_2Byte(SOCKET s, u16 reg, u16 dat)
{
HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_RESET); // 置W5500的SCS为低电平
SPI1_Send_Short(reg); // 通过SPI1写16位寄存器地址
SPI1_Send_Byte(FDM2 | RWB_WRITE | (s * 0x20 + 0x08)); // 通过SPI1写控制字节,2个字节数据长度,写数据,选择端口s的寄存器
SPI1_Send_Short(dat); // 写16位数据
HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_SET); // 置W5500的SCS为高电平
}
/*******************************************************************************
* 函数名 : Write_W5500_SOCK_4Byte
* 描述 : 通过SPI1向指定端口寄存器写4个字节数据
* 输入 : s:端口号,reg:16位寄存器地址,*dat_ptr:待写入的4个字节缓冲区指针
* 输出 : 无
* 返回值 : 无
* 说明 : 无
*******************************************************************************/
void Write_W5500_SOCK_4Byte(SOCKET s, u16 reg, u8 *dat_ptr)
{
HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_RESET); // 置W5500的SCS为低电平
SPI1_Send_Short(reg); // 通过SPI1写16位寄存器地址
SPI1_Send_Byte(FDM4 | RWB_WRITE | (s * 0x20 + 0x08)); // 通过SPI1写控制字节,4个字节数据长度,写数据,选择端口s的寄存器
SPI1_Send_Byte(*dat_ptr++); // 写第1个字节数据
SPI1_Send_Byte(*dat_ptr++); // 写第2个字节数据
SPI1_Send_Byte(*dat_ptr++); // 写第3个字节数据
SPI1_Send_Byte(*dat_ptr++); // 写第4个字节数据
HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_SET); // 置W5500的SCS为高电平
}
/*******************************************************************************
* 函数名 : Read_W5500_1Byte
* 描述 : 读W5500指定地址寄存器的1个字节数据
* 输入 : reg:16位寄存器地址
* 输出 : 无
* 返回值 : 读取到寄存器的1个字节数据
* 说明 : 无
*******************************************************************************/
u8 Read_W5500_1Byte(u16 reg)
{
u8 i;
HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_RESET); // 置W5500的SCS为低电平
SPI1_Send_Short(reg); // 通过SPI1写16位寄存器地址
SPI1_Send_Byte(FDM1 | RWB_READ | COMMON_R); // 通过SPI1写控制字节,1个字节数据长度,读数据,选择通用寄存器
i = hspi1.Instance->DR;
// HAL_SPI_Receive(&hspi1,&i,1,0xf);
// i=SPI_I2S_ReceiveData(SPI1);
SPI1_Send_Byte(0x00); // 发送一个哑数据
i = hspi1.Instance->DR;
// HAL_SPI_Receive(&hspi1,&i,1,0xf);
// i=SPI_I2S_ReceiveData(SPI1);//读取1个字节数据
HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_SET); // 置W5500的SCS为高电平
return i; // 返回读取到的寄存器数据
}
/*******************************************************************************
* 函数名 : Read_W5500_SOCK_1Byte
* 描述 : 读W5500指定端口寄存器的1个字节数据
* 输入 : s:端口号,reg:16位寄存器地址
* 输出 : 无
* 返回值 : 读取到寄存器的1个字节数据
* 说明 : 无
*******************************************************************************/
u8 Read_W5500_SOCK_1Byte(SOCKET s, u16 reg)
{
u8 i;
HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_RESET); // 置W5500的SCS为低电平
SPI1_Send_Short(reg); // 通过SPI1写16位寄存器地址
SPI1_Send_Byte(FDM1 | RWB_READ | (s * 0x20 + 0x08)); // 通过SPI1写控制字节,1个字节数据长度,读数据,选择端口s的寄存器
i = hspi1.Instance->DR;
// i=SPI_I2S_ReceiveData(SPI1);
SPI1_Send_Byte(0x00); // 发送一个哑数据
i = hspi1.Instance->DR;
// i=SPI_I2S_ReceiveData(SPI1);//读取1个字节数据
HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_SET); // 置W5500的SCS为高电平
return i; // 返回读取到的寄存器数据
}
/*******************************************************************************
* 函数名 : Read_W5500_SOCK_2Byte
* 描述 : 读W5500指定端口寄存器的2个字节数据
* 输入 : s:端口号,reg:16位寄存器地址
* 输出 : 无
* 返回值 : 读取到寄存器的2个字节数据(16位)
* 说明 : 无
*******************************************************************************/
u16 Read_W5500_SOCK_2Byte(SOCKET s, u16 reg)
{
u16 i;
HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_RESET); // 置W5500的SCS为低电平
SPI1_Send_Short(reg); // 通过SPI1写16位寄存器地址
SPI1_Send_Byte(FDM2 | RWB_READ | (s * 0x20 + 0x08)); // 通过SPI1写控制字节,2个字节数据长度,读数据,选择端口s的寄存器
i = hspi1.Instance->DR;
// i=SPI_I2S_ReceiveData(SPI1);
SPI1_Send_Byte(0x00); // 发送一个哑数据
i = hspi1.Instance->DR;
// i=SPI_I2S_ReceiveData(SPI1);//读取高位数据
SPI1_Send_Byte(0x00); // 发送一个哑数据
i *= 256;
i += hspi1.Instance->DR;
// i+=SPI_I2S_ReceiveData(SPI1);//读取低位数据
HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_SET); // 置W5500的SCS为高电平
return i; // 返回读取到的寄存器数据
}
/*******************************************************************************
* 函数名 : Read_SOCK_Data_Buffer
* 描述 : 从W5500接收数据缓冲区中读取数据
* 输入 : s:端口号,*dat_ptr:数据保存缓冲区指针
* 输出 : 无
* 返回值 : 读取到的数据长度,rx_size个字节
* 说明 : 无
*******************************************************************************/
u16 Read_SOCK_Data_Buffer(SOCKET s, u8 *dat_ptr)
{
u16 rx_size;
u16 offset, offset1;
u16 i;
u8 j;
rx_size = Read_W5500_SOCK_2Byte(s, Sn_RX_RSR);
if (rx_size == 0)
return 0; // 没接收到数据则返回
if (rx_size > 1460)
rx_size = 1460;
offset = Read_W5500_SOCK_2Byte(s, Sn_RX_RD);
offset1 = offset;
offset &= (S_RX_SIZE - 1); // 计算实际的物理地址
HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_RESET); // 置W5500的SCS为低电平
SPI1_Send_Short(offset); // 写16位地址
SPI1_Send_Byte(VDM | RWB_READ | (s * 0x20 + 0x18)); // 写控制字节,N个字节数据长度,读数据,选择端口s的寄存器
j = hspi1.Instance->DR;
// j=SPI_I2S_ReceiveData(SPI1);
if ((offset + rx_size) < S_RX_SIZE) // 如果最大地址未超过W5500接收缓冲区寄存器的最大地址
{
for (i = 0; i < rx_size; i++) // 循环读取rx_size个字节数据
{
SPI1_Send_Byte(0x00); // 发送一个哑数据
j = hspi1.Instance->DR;
// j=SPI_I2S_ReceiveData(SPI1);//读取1个字节数据
*dat_ptr = j; // 将读取到的数据保存到数据保存缓冲区
dat_ptr++; // 数据保存缓冲区指针地址自增1
}
}
else // 如果最大地址超过W5500接收缓冲区寄存器的最大地址
{
offset = S_RX_SIZE - offset;
for (i = 0; i < offset; i++) // 循环读取出前offset个字节数据
{
SPI1_Send_Byte(0x00); // 发送一个哑数据
j = hspi1.Instance->DR;
// j=SPI_I2S_ReceiveData(SPI1);//读取1个字节数据
*dat_ptr = j; // 将读取到的数据保存到数据保存缓冲区
dat_ptr++; // 数据保存缓冲区指针地址自增1
}
HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_SET); // 置W5500的SCS为高电平
HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_RESET); // 置W5500的SCS为低电平
SPI1_Send_Short(0x00); // 写16位地址
SPI1_Send_Byte(VDM | RWB_READ | (s * 0x20 + 0x18)); // 写控制字节,N个字节数据长度,读数据,选择端口s的寄存器
j = hspi1.Instance->DR;
// j=SPI_I2S_ReceiveData(SPI1);
for (; i < rx_size; i++) // 循环读取后rx_size-offset个字节数据
{
SPI1_Send_Byte(0x00); // 发送一个哑数据
j = hspi1.Instance->DR;
// j=SPI_I2S_ReceiveData(SPI1);//读取1个字节数据
*dat_ptr = j; // 将读取到的数据保存到数据保存缓冲区
dat_ptr++; // 数据保存缓冲区指针地址自增1
}
}
HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_SET); // 置W5500的SCS为高电平
offset1 += rx_size; // 更新实际物理地址,即下次读取接收到的数据的起始地址
Write_W5500_SOCK_2Byte(s, Sn_RX_RD, offset1);
Write_W5500_SOCK_1Byte(s, Sn_CR, RECV); // 发送启动接收命令
return rx_size; // 返回接收到数据的长度
}
/*******************************************************************************
* 函数名 : Write_SOCK_Data_Buffer
* 描述 : 将数据写入W5500的数据发送缓冲区
* 输入 : s:端口号,*dat_ptr:数据保存缓冲区指针,size:待写入数据的长度
* 输出 : 无
* 返回值 : 无
* 说明 : 无
*******************************************************************************/
static void Write_SOCK_Data_Buffer(bsp_W5500_Class_t *pW5500_Class, u8 *dat_ptr, u16 size)
{
u16 offset, offset1;
u16 i;
// 如果是UDP模式,可以在此设置目的主机的IP和端口号
if ((Read_W5500_SOCK_1Byte(pW5500_Class->SocketPort, Sn_MR) & 0x0f) != SOCK_UDP) // 如果Socket打开失败
{
Write_W5500_SOCK_4Byte(pW5500_Class->SocketPort, Sn_DIPR, pW5500_Class->ConfigData.UDP_DIPR); // 设置目的主机IP
Write_W5500_SOCK_2Byte(pW5500_Class->SocketPort, Sn_DPORTR, pW5500_Class->ConfigData.UDP_DPORT[0]<<8 | pW5500_Class->ConfigData.UDP_DPORT[1]); // 设置目的主机端口号
}
offset = Read_W5500_SOCK_2Byte(pW5500_Class->SocketPort, Sn_TX_WR);
offset1 = offset;
offset &= (S_TX_SIZE - 1); // 计算实际的物理地址
HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_RESET); // 置W5500的SCS为低电平
SPI1_Send_Short(offset); // 写16位地址
SPI1_Send_Byte(VDM | RWB_WRITE | (pW5500_Class->SocketPort * 0x20 + 0x10)); // 写控制字节,N个字节数据长度,写数据,选择端口s的寄存器
if ((offset + size) < S_TX_SIZE) // 如果最大地址未超过W5500发送缓冲区寄存器的最大地址
{
for (i = 0; i < size; i++) // 循环写入size个字节数据
{
SPI1_Send_Byte(*dat_ptr++); // 写入一个字节的数据
}
}
else // 如果最大地址超过W5500发送缓冲区寄存器的最大地址
{
offset = S_TX_SIZE - offset;
for (i = 0; i < offset; i++) // 循环写入前offset个字节数据
{
SPI1_Send_Byte(*dat_ptr++); // 写入一个字节的数据
}
HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_SET); // 置W5500的SCS为高电平
HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_RESET); // 置W5500的SCS为低电平
SPI1_Send_Short(0x00); // 写16位地址
SPI1_Send_Byte(VDM | RWB_WRITE | (pW5500_Class->SocketPort * 0x20 + 0x10)); // 写控制字节,N个字节数据长度,写数据,选择端口s的寄存器
for (; i < size; i++) // 循环写入size-offset个字节数据
{
SPI1_Send_Byte(*dat_ptr++); // 写入一个字节的数据
}
}
HAL_GPIO_WritePin(W5500_SCS_PORT, W5500_SCS, GPIO_PIN_SET); // 置W5500的SCS为高电平
offset1 += size; // 更新实际物理地址,即下次写待发送数据到发送数据缓冲区的起始地址
Write_W5500_SOCK_2Byte(pW5500_Class->SocketPort, Sn_TX_WR, offset1);
Write_W5500_SOCK_1Byte(pW5500_Class->SocketPort, Sn_CR, SEND); // 发送启动发送命令
}
/*******************************************************************************
* 函数名 : W5500_Hardware_Reset
* 描述 : 硬件复位W5500
* 输入 : 无
* 输出 : 无
* 返回值 : 无
* 说明 : W5500的复位引脚保持低电平至少500us以上,才能重围W5500
*******************************************************************************/
void W5500_Hardware_Reset(void)
{
HAL_GPIO_WritePin(W5500_RST_PORT, W5500_RST, GPIO_PIN_RESET); // 复位引脚拉低
HAL_Delay(50);
HAL_GPIO_WritePin(W5500_RST_PORT, W5500_RST, GPIO_PIN_SET); // 复位引脚拉高
HAL_Delay(100);
// while((Read_W5500_1Byte(PHYCFGR)&LINK)==0);//等待以太网连接完成
}
/*******************************************************************************
* 函数名 : W5500_Init
* 描述 : 初始化W5500寄存器函数
* 输入 : 无
* 输出 : 无
* 返回值 : 无
* 说明 : 在使用W5500之前,先对W5500初始化
*******************************************************************************/
void W5500_Init(void)
{
u16 i = 0;
Write_W5500_1Byte(MR, RST); // 软件复位W5500,置1有效,复位后自动清0
HAL_Delay(10); // 延时10ms,自己定义该函数
// 设置网关(Gateway)的IP地址,Gateway_IP为4字节u8数组,自己定义
// 使用网关可以使通信突破子网的局限,通过网关可以访问到其它子网或进入Internet
Write_W5500_nByte(GAR, pW5500->Gateway_IP, 4);
// 设置子网掩码(MASK)值,SUB_MASK为4字节u8数组,自己定义
// 子网掩码用于子网运算
Write_W5500_nByte(SUBR, pW5500->Sub_Mask, 4);
// 设置物理地址,PHY_ADDR为6字节u8数组,自己定义,用于唯一标识网络设备的物理地址值
// 该地址值需要到IEEE申请,按照OUI的规定,前3个字节为厂商代码,后三个字节为产品序号
// 如果自己定义物理地址,注意第一个字节必须为偶数
Write_W5500_nByte(SHAR, pW5500->Phy_Addr, 6);
// 设置本机的IP地址,IP_ADDR为4字节u8数组,自己定义
// 注意,网关IP必须与本机IP属于同一个子网,否则本机将无法找到网关
Write_W5500_nByte(SIPR, pW5500->IP_Addr, 4);
// 设置发送缓冲区和接收缓冲区的大小,参考W5500数据手册
for (i = 0; i < 8; i++)
{
Write_W5500_SOCK_1Byte(i, Sn_RXBUF_SIZE, 0x02); // Socket Rx memory size=2k
Write_W5500_SOCK_1Byte(i, Sn_TXBUF_SIZE, 0x02); // Socket Tx mempry size=2k
}
// 设置重试时间,默认为2000(200ms)
// 每一单位数值为100微秒,初始化时值设为2000(0x07D0),等于200毫秒
Write_W5500_2Byte(RTR, 0x07d0);
// 设置重试次数,默认为8次
// 如果重发的次数超过设定值,则产生超时中断(相关的端口中断寄存器中的Sn_IR 超时位(TIMEOUT)置“1”)
Write_W5500_1Byte(RCR, 8);
}
/*******************************************************************************
* 函数名 : Detect_Gateway
* 描述 : 检查网关服务器
* 输入 : 无
* 输出 : 无
* 返回值 : 成功返回TRUE(0xFF),失败返回FALSE(0x00)
* 说明 : 无
*******************************************************************************/
u8 Detect_Gateway(void)
{
u8 ip_adde[4];
ip_adde[0] = pW5500->IP_Addr[0] + 1;
ip_adde[1] = pW5500->IP_Addr[1] + 1;
ip_adde[2] = pW5500->IP_Addr[2] + 1;
ip_adde[3] = pW5500->IP_Addr[3] + 1;
// 检查网关及获取网关的物理地址
Write_W5500_SOCK_4Byte(0, Sn_DIPR, ip_adde); // 向目的地址寄存器写入与本机IP不同的IP值
Write_W5500_SOCK_1Byte(0, Sn_MR, MR_TCP); // 设置socket为TCP模式
Write_W5500_SOCK_1Byte(0, Sn_CR, OPEN); // 打开Socket
HAL_Delay(5); // 延时5ms
if (Read_W5500_SOCK_1Byte(0, Sn_SR) != SOCK_INIT) // 如果socket打开失败
{
Write_W5500_SOCK_1Byte(0, Sn_CR, CLOSE); // 打开不成功,关闭Socket
return FALSE; // 返回FALSE(0x00)
}
Write_W5500_SOCK_1Byte(0, Sn_CR, CONNECT); // 设置Socket为Connect模式
do
{
u16 j = 0;
j = Read_W5500_SOCK_1Byte(0, Sn_IR); // 读取Socket0中断标志寄存器
if (j != 0)
Write_W5500_SOCK_1Byte(0, Sn_IR, j);
HAL_Delay(5); // 延时5ms
if ((j & IR_TIMEOUT) == IR_TIMEOUT)
{
return FALSE;
}
else if (Read_W5500_SOCK_1Byte(0, Sn_DHAR) != 0xff)
{
Write_W5500_SOCK_1Byte(0, Sn_CR, CLOSE); // 关闭Socket
return TRUE;
}
} while (1);
}
/*******************************************************************************
* 函数名 : Socket_Init
* 描述 : 指定Socket(0~7)初始化
* 输入 : s:待初始化的端口
* 输出 : 无
* 返回值 : 无
* 说明 : 无
*******************************************************************************/
static void bsp_W5500_Socket_Init(bsp_W5500_Class_t *pW5500_Class)
{
Write_W5500_SOCK_2Byte(pW5500_Class->SocketPort, Sn_MSSR, 1460); // 最大分片字节数=1460(0x5b4)
Write_W5500_SOCK_2Byte(pW5500_Class->SocketPort, Sn_PORT, pW5500_Class->ConfigData.Port[0]<<8 | pW5500_Class->ConfigData.Port[1]);
// 设置端口0目的(远程)端口号
Write_W5500_SOCK_2Byte(pW5500_Class->SocketPort, Sn_DPORTR, pW5500_Class->ConfigData.DPort[0]<<8 | pW5500_Class->ConfigData.DPort[1]);
// 设置端口0目的(远程)IP地址
Write_W5500_SOCK_4Byte(pW5500_Class->SocketPort, Sn_DIPR, pW5500_Class->ConfigData.DIP);
}
/*******************************************************************************
* 函数名 : Socket_Connect
* 描述 : 设置指定Socket(0~7)为客户端与远程服务器连接
* 输入 : s:待设定的端口
* 输出 : 无
* 返回值 : 成功返回TRUE(0xFF),失败返回FALSE(0x00)
* 说明 : 当本机Socket工作在客户端模式时,引用该程序,与远程服务器建立连接
* 如果启动连接后出现超时中断,则与服务器连接失败,需要重新调用该程序连接
* 该程序每调用一次,就与服务器产生一次连接
*******************************************************************************/
u8 Socket_Connect(SOCKET s)
{
Write_W5500_SOCK_1Byte(s, Sn_MR, MR_TCP); // 设置socket为TCP模式
Write_W5500_SOCK_1Byte(s, Sn_CR, OPEN); // 打开Socket
HAL_Delay(5); // 延时5ms
if (Read_W5500_SOCK_1Byte(s, Sn_SR) != SOCK_INIT) // 如果socket打开失败
{
Write_W5500_SOCK_1Byte(s, Sn_CR, CLOSE); // 打开不成功,关闭Socket
return FALSE; // 返回FALSE(0x00)
}
Write_W5500_SOCK_1Byte(s, Sn_CR, CONNECT); // 设置Socket为Connect模式
return TRUE; // 返回TRUE,设置成功
}
/*******************************************************************************
* 函数名 : Socket_Listen
* 描述 : 设置指定Socket(0~7)作为服务器等待远程主机的连接
* 输入 : s:待设定的端口
* 输出 : 无
* 返回值 : 成功返回TRUE(0xFF),失败返回FALSE(0x00)
* 说明 : 当本机Socket工作在服务器模式时,引用该程序,等等远程主机的连接
* 该程序只调用一次,就使W5500设置为服务器模式
*******************************************************************************/
u8 Socket_Listen(SOCKET s)
{
Write_W5500_SOCK_1Byte(s, Sn_MR, MR_TCP); // 设置socket为TCP模式
Write_W5500_SOCK_1Byte(s, Sn_CR, OPEN); // 打开Socket
HAL_Delay(5); // 延时5ms
if (Read_W5500_SOCK_1Byte(s, Sn_SR) != SOCK_INIT) // 如果socket打开失败
{
Write_W5500_SOCK_1Byte(s, Sn_CR, CLOSE); // 打开不成功,关闭Socket
return FALSE; // 返回FALSE(0x00)
}
Write_W5500_SOCK_1Byte(s, Sn_CR, LISTEN); // 设置Socket为侦听模式
HAL_Delay(5); // 延时5ms
if (Read_W5500_SOCK_1Byte(s, Sn_SR) != SOCK_LISTEN) // 如果socket设置失败
{
Write_W5500_SOCK_1Byte(s, Sn_CR, CLOSE); // 设置不成功,关闭Socket
return FALSE; // 返回FALSE(0x00)
}
return TRUE;
// 至此完成了Socket的打开和设置侦听工作,至于远程客户端是否与它建立连接,则需要等待Socket中断,
// 以判断Socket的连接是否成功。参考W5500数据手册的Socket中断状态
// 在服务器侦听模式不需要设置目的IP和目的端口号
}
/*******************************************************************************
* 函数名 : Socket_UDP
* 描述 : 设置指定Socket(0~7)为UDP模式
* 输入 : s:待设定的端口
* 输出 : 无
* 返回值 : 成功返回TRUE(0xFF),失败返回FALSE(0x00)
* 说明 : 如果Socket工作在UDP模式,引用该程序,在UDP模式下,Socket通信不需要建立连接
* 该程序只调用一次,就使W5500设置为UDP模式
*******************************************************************************/
u8 Socket_UDP(SOCKET s)
{
Write_W5500_SOCK_1Byte(s, Sn_MR, MR_UDP); // 设置Socket为UDP模式*/
Write_W5500_SOCK_1Byte(s, Sn_CR, OPEN); // 打开Socket*/
HAL_Delay(5); // 延时5ms
if (Read_W5500_SOCK_1Byte(s, Sn_SR) != SOCK_UDP) // 如果Socket打开失败
{
Write_W5500_SOCK_1Byte(s, Sn_CR, CLOSE); // 打开不成功,关闭Socket
return FALSE; // 返回FALSE(0x00)
}
else
return TRUE;
// 至此完成了Socket的打开和UDP模式设置,在这种模式下它不需要与远程主机建立连接
// 因为Socket不需要建立连接,所以在发送数据前都可以设置目的主机IP和目的Socket的端口号
// 如果目的主机IP和目的Socket的端口号是固定的,在运行过程中没有改变,那么也可以在这里设置
}
/*******************************************************************************
* 函数名 : W5500_Interrupt_Process
* 描述 : W5500中断处理程序框架
* 输入 : 无
* 输出 : 无
* 返回值 : 无
* 说明 : 无
*******************************************************************************/
static void bsp_W5500_Interrupt_Process(void)
{
u8 i, j;
u8 Int_Flag,Socket_Flag;
IntDispose:
Int_Flag = Read_W5500_1Byte(SIR); // 读取端口中断标志寄存器
HAL_Delay(10);
for(i=0;i<BSP_W5500_PORT_NUM;i++)
{
if(Int_Flag & (0x01 << i))
{
Socket_Flag = Read_W5500_SOCK_1Byte(pW5500->W5500_Class[i].SocketPort, Sn_IR); // 读取Socket0中断标志寄存器
Write_W5500_SOCK_1Byte(pW5500->W5500_Class[i].SocketPort, Sn_IR, Socket_Flag);
if (Socket_Flag & IR_CON) // 在TCP模式下,Socket0成功连接
{
pW5500->W5500_Class[i].Run_State |= BSP_W5500_PORT_RUN_STATE_CONN; // 网络连接状态0x02,端口完成连接,可以正常传输数据
}
if (Socket_Flag & IR_DISCON) // 在TCP模式下Socket断开连接处理
{
Write_W5500_SOCK_1Byte(pW5500->W5500_Class[i].SocketPort, Sn_CR, CLOSE); // 关闭端口,等待重新打开连接
bsp_W5500_Socket_Init(&pW5500->W5500_Class[i]); // 指定Socket(0~7)初始化,初始化端口0
pW5500->W5500_Class[i].Run_State = 0; // 网络连接状态0x00,端口连接失败
}
if (Socket_Flag & IR_SEND_OK) // Socket0数据发送完成,可以再次启动S_tx_process()函数发送数据
{
pW5500->W5500_Class[i].TR_Data_State |= BSP_W5500_PORT_DATA_TRANSMITOK; // 端口发送一个数据包完成
}
if (Socket_Flag & IR_RECV) // Socket接收到数据,可以启动S_rx_process()函数
{
pW5500->W5500_Class[i].TR_Data_State |= BSP_W5500_PORT_DATA_RECEIVE; // 端口接收到一个数据包
}
if (Socket_Flag & IR_TIMEOUT) // Socket连接或数据传输超时处理
{
Write_W5500_SOCK_1Byte(pW5500->W5500_Class[i].SocketPort, Sn_CR, CLOSE); // 关闭端口,等待重新打开连接
pW5500->W5500_Class[i].TR_Data_State = 0; // 网络连接状态0x00,端口连接失败
}
}
}
if (Read_W5500_1Byte(SIR) != 0)
goto IntDispose;
}
void bsp_W5500_Socket_Set(bsp_W5500_Class_t *pW5500_Class)
{
if (0 == pW5500_Class->Run_State)
{
switch(pW5500_Class->Run_Mode)
{
/*TCP服务器模式*/
case BSP_W5500_PORT_RUN_MODE_TCP_SERVER:
{
if (Socket_Listen(pW5500_Class->SocketPort) == TRUE)
pW5500_Class->Run_State = BSP_W5500_PORT_RUN_STATE_INIT;
else
pW5500_Class->Run_State = 0;
}break;
/*TCP客户端模式*/
case BSP_W5500_PORT_RUN_MODE_TCP_CLIENT:
{
if(Socket_Connect(pW5500_Class->SocketPort)==TRUE)
pW5500_Class->Run_State = BSP_W5500_PORT_RUN_STATE_INIT;
else
pW5500_Class->Run_State = 0;
}break;
/*UDP模式*/
case BSP_W5500_PORT_RUN_MODE_UDP:
{
if(Socket_UDP(pW5500_Class->SocketPort)==TRUE)
pW5500_Class->Run_State = BSP_W5500_PORT_RUN_STATE_INIT | BSP_W5500_PORT_RUN_STATE_CONN;
else
pW5500_Class->Run_State = 0;
}break;
default:break;
}
}
}
static void bsp_W5500_Init()
{
u8 i;
W5500_Hardware_Reset(); /*硬件复位W5500*/
W5500_Init(); /*初始化W5500寄存器函数*/
Detect_Gateway(); /*检查网关服务器*/
for(i=0;i<BSP_W5500_PORT_NUM;i++)
{
bsp_W5500_Socket_Init(&pW5500->W5500_Class[i]);
pW5500->W5500_Class[i].Run_State = 0; /*复位状态*/
// bsp_W5500_Socket_Set(&pW5500->W5500_Class[i]); /*W5500端口初始化配置*/
}
}
static void bsp_W5500_Task(void)
{
u8 i;
for(i=0;i<BSP_W5500_PORT_NUM;i++)
{
bsp_W5500_Socket_Set(&pW5500->W5500_Class[i]); /*W5500端口初始化配置*/
}
bsp_W5500_Interrupt_Process(); // W5500中断处理程序框架
for(i=0;i<BSP_W5500_PORT_NUM;i++)
{
if ((pW5500->W5500_Class[i].TR_Data_State & BSP_W5500_PORT_DATA_RECEIVE) == BSP_W5500_PORT_DATA_RECEIVE) // 如果Socket0接收到数据
{
pW5500->W5500_Class[i].TR_Data_State &= ~BSP_W5500_PORT_DATA_RECEIVE;
u16 Len = Read_SOCK_Data_Buffer(0, pW5500->W5500_Class[i].Rx_Buffer);
// Write_SOCK_Data_Buffer(&pW5500->W5500_Class[i], pW5500->W5500_Class[i].Rx_Buffer, Len);
// printf("RX");
// Debug_UartSend(pW5500->W5500_Class[i].Rx_Buffer, Len);
if(pW5500->W5500_Class[i].Rx_DataAnalysis != NULL)
{
pW5500->W5500_Class[i].Rx_DataAnalysis(&pW5500->W5500_Class[i],pW5500->W5500_Class[i].Rx_Buffer,Len);/*数据解析*/
}
}
}
}
+274
View File
@@ -0,0 +1,274 @@
#ifndef _W5500_H_
#define _W5500_H_
#include "main.h"
/***************** Common Register *****************/
#define MR 0x0000
#define RST 0x80
#define WOL 0x20
#define PB 0x10
#define PPP 0x08
#define FARP 0x02
#define GAR 0x0001
#define SUBR 0x0005
#define SHAR 0x0009
#define SIPR 0x000f
#define INTLEVEL 0x0013
#define IR 0x0015
#define CONFLICT 0x80
#define UNREACH 0x40
#define PPPOE 0x20
#define MP 0x10
#define IMR 0x0016
#define IM_IR7 0x80
#define IM_IR6 0x40
#define IM_IR5 0x20
#define IM_IR4 0x10
#define SIR 0x0017
#define S7_INT 0x80
#define S6_INT 0x40
#define S5_INT 0x20
#define S4_INT 0x10
#define S3_INT 0x08
#define S2_INT 0x04
#define S1_INT 0x02
#define S0_INT 0x01
#define SIMR 0x0018
#define S7_IMR 0x80
#define S6_IMR 0x40
#define S5_IMR 0x20
#define S4_IMR 0x10
#define S3_IMR 0x08
#define S2_IMR 0x04
#define S1_IMR 0x02
#define S0_IMR 0x01
#define RTR 0x0019
#define RCR 0x001b
#define PTIMER 0x001c
#define PMAGIC 0x001d
#define PHA 0x001e
#define PSID 0x0024
#define PMRU 0x0026
#define UIPR 0x0028
#define UPORT 0x002c
#define PHYCFGR 0x002e
#define RST_PHY 0x80
#define OPMODE 0x40
#define DPX 0x04
#define SPD 0x02
#define LINK 0x01
#define VERR 0x0039
/********************* Socket Register *******************/
#define Sn_MR 0x0000
#define MULTI_MFEN 0x80
#define BCASTB 0x40
#define ND_MC_MMB 0x20
#define UCASTB_MIP6B 0x10
#define MR_CLOSE 0x00
#define MR_TCP 0x01
#define MR_UDP 0x02
#define MR_MACRAW 0x04
#define Sn_CR 0x0001
#define OPEN 0x01
#define LISTEN 0x02
#define CONNECT 0x04
#define DISCON 0x08
#define CLOSE 0x10
#define SEND 0x20
#define SEND_MAC 0x21
#define SEND_KEEP 0x22
#define RECV 0x40
#define Sn_IR 0x0002
#define IR_SEND_OK 0x10
#define IR_TIMEOUT 0x08
#define IR_RECV 0x04
#define IR_DISCON 0x02
#define IR_CON 0x01
#define Sn_SR 0x0003
#define SOCK_CLOSED 0x00
#define SOCK_INIT 0x13
#define SOCK_LISTEN 0x14
#define SOCK_ESTABLISHED 0x17
#define SOCK_CLOSE_WAIT 0x1c
#define SOCK_UDP 0x22
#define SOCK_MACRAW 0x02
#define SOCK_SYNSEND 0x15
#define SOCK_SYNRECV 0x16
#define SOCK_FIN_WAI 0x18
#define SOCK_CLOSING 0x1a
#define SOCK_TIME_WAIT 0x1b
#define SOCK_LAST_ACK 0x1d
#define Sn_PORT 0x0004
#define Sn_DHAR 0x0006
#define Sn_DIPR 0x000c
#define Sn_DPORTR 0x0010
#define Sn_MSSR 0x0012
#define Sn_TOS 0x0015
#define Sn_TTL 0x0016
#define Sn_RXBUF_SIZE 0x001e
#define Sn_TXBUF_SIZE 0x001f
#define Sn_TX_FSR 0x0020
#define Sn_TX_RD 0x0022
#define Sn_TX_WR 0x0024
#define Sn_RX_RSR 0x0026
#define Sn_RX_RD 0x0028
#define Sn_RX_WR 0x002a
#define Sn_IMR 0x002c
#define IMR_SENDOK 0x10
#define IMR_TIMEOUT 0x08
#define IMR_RECV 0x04
#define IMR_DISCON 0x02
#define IMR_CON 0x01
#define Sn_FRAG 0x002d
#define Sn_KPALVTR 0x002f
/*******************************************************************/
/************************ SPI Control Byte *************************/
/*******************************************************************/
/* Operation mode bits */
#define VDM 0x00
#define FDM1 0x01
#define FDM2 0x02
#define FDM4 0x03
/* Read_Write control bit */
#define RWB_READ 0x00
#define RWB_WRITE 0x04
/* Block select bits */
#define COMMON_R 0x00
/* Socket 0 */
#define S0_REG 0x08
#define S0_TX_BUF 0x10
#define S0_RX_BUF 0x18
/* Socket 1 */
#define S1_REG 0x28
#define S1_TX_BUF 0x30
#define S1_RX_BUF 0x38
/* Socket 2 */
#define S2_REG 0x48
#define S2_TX_BUF 0x50
#define S2_RX_BUF 0x58
/* Socket 3 */
#define S3_REG 0x68
#define S3_TX_BUF 0x70
#define S3_RX_BUF 0x78
/* Socket 4 */
#define S4_REG 0x88
#define S4_TX_BUF 0x90
/* Socket 5 */
#define S5_REG 0xa8
#define S5_TX_BUF 0xb0
#define S5_RX_BUF 0xb8
/* Socket 6 */
#define S6_REG 0xc8
#define S6_TX_BUF 0xd0
#define S6_RX_BUF 0xd8
/* Socket 7 */
#define S7_REG 0xe8
#define S7_TX_BUF 0xf0
#define S7_RX_BUF 0xf8
#define TRUE 0xff
#define FALSE 0x00
#define S_RX_SIZE 2048 /*定义Socket接收缓冲区的大小,可以根据W5500_RMSR的设置修改 */
#define S_TX_SIZE 2048 /*定义Socket发送缓冲区的大小,可以根据W5500_TMSR的设置修改 */
/***************----- W5500 GPIO定义 -----***************/
#define W5500_SCS W5500_SPI1_CS_Pin // 定义W5500的CS引脚
#define W5500_SCS_PORT W5500_SPI1_CS_GPIO_Port
#define W5500_RST W5500_RST_Pin // 定义W5500的RST引脚
#define W5500_RST_PORT W5500_RST_GPIO_Port
#define W5500_INT W5500_INT_Pin // 定义W5500的INT引脚
#define W5500_INT_PORT W5500_INT_GPIO_Port
typedef u8 SOCKET; // 自定义端口号数据类型
#define BSP_W5500_PORT_NUM 1
#define BSP_W5500_DATA_LEN 2048
typedef struct bsp_W5500_Class_t bsp_W5500_Class_t;
struct bsp_W5500_Class_t
{
SOCKET SocketPort;
struct
{
/***************----- 网络参数变量定义 -----***************/
u8 Gateway_IP[4]; /*网关IP地址*/
u8 Sub_Mask[4]; /*子网掩码*/
u8 Phy_Addr[6]; /*物理地址(MAC)*/
u8 IP_Addr[4]; /*本机IP地址*/
u8 Port[2]; /*端口0的端口号(5000) */
u8 DIP[4]; /*端口0目的IP地址*/
u8 DPort[2]; /*端口0目的端口号(6000)*/
u8 UDP_DIPR[4]; /*UDP(广播)模式,目的主机IP地址*/
u8 UDP_DPORT[2]; /*UDP(广播)模式,目的主机端口号*/
}ConfigData;
/***************----- 端口的运行模式 -----***************/
u8 Run_Mode;
/***************----- 端口的运行状态 -----***************/
u8 Run_State;
/***************----- 端口收发数据的状态 -----***********/
u8 TR_Data_State;
/***************----- 端口数据缓冲区 -----***************/
u8 Rx_Buffer[BSP_W5500_DATA_LEN]; // 端口接收数据缓冲区
u8 Tx_Buffer[BSP_W5500_DATA_LEN]; // 端口发送数据缓冲区
u8 Interrupt; // W5500中断标志(0:无中断,1:有中断)
void (*Rx_DataAnalysis)(bsp_W5500_Class_t *,u8 *,u16 );
};
typedef struct
{
u8 Gateway_IP[4]; /*网关IP地址*/
u8 Sub_Mask[4]; /*子网掩码*/
u8 Phy_Addr[6]; /*物理地址(MAC)*/
u8 IP_Addr[4]; /*本机IP地址*/
bsp_W5500_Class_t W5500_Class[BSP_W5500_PORT_NUM]; /*端口成员*/
void (*Interrupt_Process)(void); /*处理进程*/
void (*Init)(void); /*初始化*/
void (*Task)(void); /*任务*/
void (*Socket_Send)(bsp_W5500_Class_t *, u8 *, u16 ); /*端口发送数据*/
}bsp_W5500_t;
extern bsp_W5500_t W5500;
#endif
+25
View File
@@ -0,0 +1,25 @@
#include "bsp_Wdg.h"
//#include "iwdg.h"
static void bsp_Wdg_Init(void);
static void bsp_Wdg_Feed(void);
bsp_Wdg_t Wdg =
{
.Init = bsp_Wdg_Init,
.Feed = bsp_Wdg_Feed,
};
bsp_Wdg_t *pWdg = &Wdg;
static void bsp_Wdg_Init(void)
{
// __HAL_DBGMCU_FREEZE_IWDG(); //调试模式下,冻结看门狗计数器时钟
}
static void bsp_Wdg_Feed(void)
{
// HAL_IWDG_Refresh(&hiwdg);
}
+13
View File
@@ -0,0 +1,13 @@
#ifndef _BSP_WDG_H_
#define _BSP_WDG_H_
#include "main.h"
typedef struct
{
void (*Init)(void);
void (*Feed)(void);
}bsp_Wdg_t;
extern bsp_Wdg_t Wdg;
#endif
+85
View File
@@ -0,0 +1,85 @@
#include "bsp_buzzer.h"
/*开关控制电平,使用同一的电平控制方式*/
#define BUZZER_GPIO_ON GPIO_PIN_SET
#define BUZZER_GPIO_OFF GPIO_PIN_RESET
#define BUZZER_ON HAL_GPIO_WritePin (BUZZER_GPIO_Port, BUZZER_Pin, BUZZER_GPIO_ON)
#define BUZZER_OFF HAL_GPIO_WritePin (BUZZER_GPIO_Port, BUZZER_Pin, BUZZER_GPIO_OFF)
static void bsp_buzzer_init(void);
static void bsp_buzzer_task(void);
static void bsp_buzzer_set(u8 ch,u8 state);
static void bsp_buzzer_on(void);
static void bsp_buzzer_off(void);
static void bsp_buzzer_enable(void);
static void bsp_buzzer_disable(void);
bsp_buzzer_t buzzer =
{
.init = bsp_buzzer_init,
.task = bsp_buzzer_task,
.set.on = bsp_buzzer_on,
.set.off = bsp_buzzer_off,
.set.enable = bsp_buzzer_enable,
.set.disable = bsp_buzzer_disable,
};
bsp_buzzer_t *p_buzzer = &buzzer;
static bsp_buzzer_flash_data_t flash_data;
/*其他外设初始化后快速闪烁,提示初始化完成*/
static void bsp_buzzer_init(void)
{
BUZZER_OFF;
p_buzzer->p_flash_data = &flash_data;
}
static void bsp_buzzer_flash_data_save(void)
{
}
static void bsp_buzzer_task(void)
{
if(USR_DISABLE == p_buzzer->p_flash_data->sw)
{
BUZZER_OFF;
}
else if( USR_ON == p_buzzer->state)
{
BUZZER_ON;
}
else
{
BUZZER_OFF;
}
}
static void bsp_buzzer_on(void)
{
p_buzzer->state = USR_ON;
}
static void bsp_buzzer_off(void)
{
p_buzzer->state = USR_OFF;
}
static void bsp_buzzer_enable(void)
{
if(USR_ENABLE != p_buzzer->p_flash_data->sw)
{
p_buzzer->p_flash_data->sw = USR_ENABLE;
bsp_buzzer_flash_data_save();
}
}
static void bsp_buzzer_disable(void)
{
if(USR_DISABLE != p_buzzer->p_flash_data->sw)
{
p_buzzer->p_flash_data->sw = USR_DISABLE;
bsp_buzzer_flash_data_save();
}
}
+30
View File
@@ -0,0 +1,30 @@
#ifndef _BSP_buzzer_H_
#define _BSP_buzzer_H_
#include "main.h"
/*ʹÄÜ¿ª¹Ø*/
typedef struct
{
u8 sw;
}bsp_buzzer_flash_data_t;
typedef struct
{
u8 state;
bsp_buzzer_flash_data_t *p_flash_data;
void (*init)(void);
void (*task)(void);
struct
{
void (*on)(void);
void (*off)(void);
void (*enable)(void);
void (*disable)(void);
}set;
}bsp_buzzer_t;
extern bsp_buzzer_t buzzer;
#endif
+54
View File
@@ -0,0 +1,54 @@
#include "bsp_relay.h"
/*开关控制电平,使用同一的电平控制方式*/
#define RELAY_GPIO_ON GPIO_PIN_SET
#define RELAY_GPIO_OFF GPIO_PIN_RESET
#define RELAY_1_ON HAL_GPIO_WritePin (RELAY_1_GPIO_Port, RELAY_1_Pin, RELAY_GPIO_ON)
#define RELAY_1_OFF HAL_GPIO_WritePin (RELAY_1_GPIO_Port, RELAY_1_Pin, RELAY_GPIO_OFF)
#define RELAY_2_ON HAL_GPIO_WritePin (RELAY_2_GPIO_Port, RELAY_2_Pin, RELAY_GPIO_ON)
#define RELAY_2_OFF HAL_GPIO_WritePin (RELAY_2_GPIO_Port, RELAY_2_Pin, RELAY_GPIO_OFF)
#define RELAY_3_ON HAL_GPIO_WritePin (RELAY_3_GPIO_Port, RELAY_3_Pin, RELAY_GPIO_ON)
#define RELAY_3_OFF HAL_GPIO_WritePin (RELAY_3_GPIO_Port, RELAY_3_Pin, RELAY_GPIO_OFF)
#define RELAY_4_ON HAL_GPIO_WritePin (RELAY_4_GPIO_Port, RELAY_4_Pin, RELAY_GPIO_ON)
#define RELAY_4_OFF HAL_GPIO_WritePin (RELAY_4_GPIO_Port, RELAY_4_Pin, RELAY_GPIO_OFF)
static void bsp_relay_init(void);
static void bsp_relay_task(void);
static void bsp_relay_set(u8 ch,u8 state);
bsp_relay_t relay =
{
.init = bsp_relay_init,
.task = bsp_relay_task,
.set = bsp_relay_set,
};
bsp_relay_t *p_relay = &relay;
/*其他外设初始化后快速闪烁,提示初始化完成*/
static void bsp_relay_init(void)
{
RELAY_1_OFF;
RELAY_2_OFF;
RELAY_3_OFF;
RELAY_4_OFF;
}
static void bsp_relay_task(void)
{
(USR_ON == p_relay->state[0]) ? RELAY_1_ON : RELAY_1_OFF;
(USR_ON == p_relay->state[1]) ? RELAY_2_ON : RELAY_2_OFF;
(USR_ON == p_relay->state[2]) ? RELAY_3_ON : RELAY_3_OFF;
(USR_ON == p_relay->state[3]) ? RELAY_4_ON : RELAY_4_OFF;
}
/*控制对应通道状态*/
static void bsp_relay_set(u8 ch,u8 state)
{
if(ch < BSP_RELAY_CH_NUM)
{
p_relay->state[ch] = state;
}
}
+23
View File
@@ -0,0 +1,23 @@
#ifndef _BSP_RELAY_H_
#define _BSP_RELAY_H_
#include "main.h"
#define BSP_RELAY_CH_NUM (4)
#define BSP_RELAY_CH_LEAKAGE (0)/*漏液通道*/
#define BSP_RELAY_CH_OPEN (1)/*断带*/
#define BSP_RELAY_CH_COMMINCAION (2)/*通讯异常*/
#define BSP_RELAY_CH_ERROR_STATE (3)/*状态异常报警*/
typedef struct
{
u8 state[BSP_RELAY_CH_NUM];
void (*init)(void);
void (*task)(void);
void (*set)(u8 ,u8 );
}bsp_relay_t;
extern bsp_relay_t relay;
#endif
+663
View File
@@ -0,0 +1,663 @@
#include "bsp_uart.h"
#include "string.h"
/* RS485控制宏定义 */
#define RS485_1_RX HAL_GPIO_WritePin(RS485_1_EN_GPIO_Port, RS485_1_EN_Pin, GPIO_PIN_RESET)
#define RS485_1_TX HAL_GPIO_WritePin(RS485_1_EN_GPIO_Port, RS485_1_EN_Pin, GPIO_PIN_SET)
#define RS485_2_RX HAL_GPIO_WritePin(RS485_2_EN_GPIO_Port, RS485_2_EN_Pin, GPIO_PIN_RESET)
#define RS485_2_TX HAL_GPIO_WritePin(RS485_2_EN_GPIO_Port, RS485_2_EN_Pin, GPIO_PIN_SET)
#define RS485_3_RX HAL_GPIO_WritePin(RS485_3_EN_GPIO_Port, RS485_3_EN_Pin, GPIO_PIN_RESET)
#define RS485_3_TX HAL_GPIO_WritePin(RS485_3_EN_GPIO_Port, RS485_3_EN_Pin, GPIO_PIN_SET)
#define RS485_4_RX HAL_GPIO_WritePin(RS485_4_EN_GPIO_Port, RS485_4_EN_Pin, GPIO_PIN_RESET)
#define RS485_4_TX HAL_GPIO_WritePin(RS485_4_EN_GPIO_Port, RS485_4_EN_Pin, GPIO_PIN_SET)
/* 缓冲收发区大小 */
#define RX_TEMP_BUFF_NUM (128U)
/* UART缓冲区大小定义 */
#define UART1_TX_LEN (128U)
#define UART1_RX_LEN (128U)
#define UART2_TX_LEN (128U)
#define UART2_RX_LEN (128U)
#define UART3_TX_LEN (128U)
#define UART3_RX_LEN (128U)
#define UART4_TX_LEN (128U)
#define UART4_RX_LEN (128U)
#define UART6_TX_LEN (128U)
#define UART6_RX_LEN (128U)
/* 全局缓冲区变量 */
u8 uart1_tx_buff[UART1_TX_LEN];
u8 uart1_rx_buff[UART1_RX_LEN];
u8 uart2_tx_buff[UART2_TX_LEN];
u8 uart2_rx_buff[UART2_RX_LEN];
u8 uart3_tx_buff[UART3_TX_LEN];
u8 uart3_rx_buff[UART3_RX_LEN];
u8 uart4_tx_buff[UART4_TX_LEN];
u8 uart4_rx_buff[UART4_RX_LEN];
u8 uart6_tx_buff[UART6_TX_LEN];
u8 uart6_rx_buff[UART6_RX_LEN];
u8 rx_temp_buff[RX_TEMP_BUFF_NUM];
/* 函数声明 */
static void bsp_uart_init(bsp_uart_t *p_uart);
static void bsp_uart_send(bsp_uart_t *p_uart, u8 *p_data, u16 len);
static void bsp_uart_rx_idle_int(bsp_uart_t *p_uart);
static void bsp_uart_rx_time_increment(bsp_uart_t *p_uart, u16 time);
static void bsp_uart_rx_task(bsp_uart_t *p_uart);
static void bsp_uart_rx_time_start(bsp_uart_t *p_uart);
static void bsp_uart_tx_dma_tc_int(bsp_uart_t *p_uart);
static void bsp_uart_dma_send(bsp_uart_t *p_uart, u8 *p_data, u16 len);
static void bsp_uart_baud_rate_set(bsp_uart_t *p_uart,u16 baud_rate);
/* 外部HAL句柄声明 */
extern UART_HandleTypeDef huart1;
extern UART_HandleTypeDef huart2;
extern UART_HandleTypeDef huart3;
extern UART_HandleTypeDef huart4;
extern UART_HandleTypeDef huart6;
extern DMA_HandleTypeDef hdma_usart1_rx;
extern DMA_HandleTypeDef hdma_usart1_tx;
extern DMA_HandleTypeDef hdma_usart2_rx;
extern DMA_HandleTypeDef hdma_usart2_tx;
extern DMA_HandleTypeDef hdma_usart3_rx;
extern DMA_HandleTypeDef hdma_usart3_tx;
extern DMA_HandleTypeDef hdma_uart4_rx;
extern DMA_HandleTypeDef hdma_uart4_tx;
extern DMA_HandleTypeDef hdma_usart6_rx;
extern DMA_HandleTypeDef hdma_usart6_tx;
/******************************************
* 结构体: com_uart1
* 功能: UART1控制实例
* 描述: 定义UART1的硬件参数和回调函数
*******************************************/
bsp_uart_t com_uart1 =
{
.rx_queue = queue(u8, UART1_RX_LEN),
.uart = &huart1,
.tx_dma = &hdma_usart1_tx,
.rx_dma = &hdma_usart1_rx,
.tx_dma_len = UART1_TX_LEN,
.rx_dma_len = UART1_RX_LEN,
.tx_addr = &uart1_tx_buff[0],
.rx_addr = &uart1_rx_buff[0],
.tx_dma_complete_flag = 1,
.rx_time_over = 0,
.relay.uart = NULL,
.init = bsp_uart_init,
.send = bsp_uart_send,
.set = bsp_uart_baud_rate_set,
.tx_dma_tc_int = bsp_uart_tx_dma_tc_int,
.rx_idle_int = bsp_uart_rx_idle_int,
.rx_time_increment_int = bsp_uart_rx_time_increment,
.rx_data_analysis = NULL,
.rx_task = bsp_uart_rx_task,
};
/******************************************
* 结构体: com_uart2
* 功能: UART2控制实例
* 描述: 定义UART2的硬件参数和回调函数
*******************************************/
bsp_uart_t com_uart2 =
{
.rx_queue = queue(u8, UART2_RX_LEN),
.uart = &huart2,
.tx_dma = &hdma_usart2_tx,
.rx_dma = &hdma_usart2_rx,
.tx_dma_len = UART2_TX_LEN,
.rx_dma_len = UART2_RX_LEN,
.tx_addr = &uart2_tx_buff[0],
.rx_addr = &uart2_rx_buff[0],
.tx_dma_complete_flag = 1,
.rx_time_over = 0,
.relay.uart = &com_uart4,
.set = bsp_uart_baud_rate_set,
.init = bsp_uart_init,
.send = bsp_uart_send,
.tx_dma_tc_int = bsp_uart_tx_dma_tc_int,
.rx_idle_int = bsp_uart_rx_idle_int,
.rx_time_increment_int = bsp_uart_rx_time_increment,
.rx_data_analysis = NULL,
.rx_task = bsp_uart_rx_task,
};
/******************************************
* 结构体: com_uart3
* 功能: UART2控制实例
* 描述: 定义UART2的硬件参数和回调函数
*******************************************/
bsp_uart_t com_uart3 =
{
.rx_queue = queue(u8, UART3_RX_LEN),
.uart = &huart3,
.tx_dma = &hdma_usart3_tx,
.rx_dma = &hdma_usart3_rx,
.tx_dma_len = UART3_TX_LEN,
.rx_dma_len = UART3_RX_LEN,
.tx_addr = &uart3_tx_buff[0],
.rx_addr = &uart3_rx_buff[0],
.tx_dma_complete_flag = 1,
.rx_time_over = 0,
.relay.uart = &com_uart3,
.set = bsp_uart_baud_rate_set,
.init = bsp_uart_init,
.send = bsp_uart_send,
.tx_dma_tc_int = bsp_uart_tx_dma_tc_int,
.rx_idle_int = bsp_uart_rx_idle_int,
.rx_time_increment_int = bsp_uart_rx_time_increment,
.rx_data_analysis = NULL,
.rx_task = bsp_uart_rx_task,
};
/******************************************
* 结构体: com_uart4
* 功能: UART4控制实例
* 描述: 定义UART4的硬件参数和回调函数
*******************************************/
bsp_uart_t com_uart4 =
{
.rx_queue = queue(u8, UART4_RX_LEN),
.uart = &huart4,
.tx_dma = &hdma_uart4_tx,
.rx_dma = &hdma_uart4_rx,
.tx_dma_len = UART4_TX_LEN,
.rx_dma_len = UART4_RX_LEN,
.tx_addr = &uart4_tx_buff[0],
.rx_addr = &uart4_rx_buff[0],
.tx_dma_complete_flag = 1,
.rx_time_over = 0,
.relay.uart = NULL,
.set = bsp_uart_baud_rate_set,
.init = bsp_uart_init,
.send = bsp_uart_send,
.tx_dma_tc_int = bsp_uart_tx_dma_tc_int,
.rx_idle_int = bsp_uart_rx_idle_int,
.rx_time_increment_int = bsp_uart_rx_time_increment,
.rx_data_analysis = NULL,
.rx_task = bsp_uart_rx_task,
};
/******************************************
* 结构体: com_uart6
* 功能: UART6控制实例
* 描述: 定义UART4的硬件参数和回调函数
*******************************************/
bsp_uart_t com_uart6 =
{
.rx_queue = queue(u8, UART6_RX_LEN),
.uart = &huart6,
.tx_dma = &hdma_usart6_tx,
.rx_dma = &hdma_usart6_rx,
.tx_dma_len = UART6_TX_LEN,
.rx_dma_len = UART6_RX_LEN,
.tx_addr = &uart6_tx_buff[0],
.rx_addr = &uart6_rx_buff[0],
.tx_dma_complete_flag = 1,
.rx_time_over = 0,
.relay.uart = NULL,
.set = bsp_uart_baud_rate_set,
.init = bsp_uart_init,
.send = bsp_uart_send,
.tx_dma_tc_int = bsp_uart_tx_dma_tc_int,
.rx_idle_int = bsp_uart_rx_idle_int,
.rx_time_increment_int = bsp_uart_rx_time_increment,
.rx_data_analysis = NULL,
.rx_task = bsp_uart_rx_task,
};
/******************************************
* 函数: bsp_uart_init
* 功能: UART初始化
* 参数: p_uart - 指向UART结构体的指针
* 返回: 无
* 描述: 初始化UART,使能空闲中断和DMA接收
*******************************************/
static void bsp_uart_init(bsp_uart_t *p_uart)
{
/* 启用空闲中断 */
__HAL_UART_ENABLE_IT(p_uart->uart, UART_IT_IDLE);
/* 重新启动接收,使用空闲中断模式 */
HAL_UARTEx_ReceiveToIdle_DMA(p_uart->uart, p_uart->rx_addr, p_uart->rx_dma_len);
}
static void bsp_uart_baud_rate_set(bsp_uart_t *p_uart,u16 baud_rate)
{
p_uart->uart->Init.BaudRate = baud_rate;
HAL_UART_Init(p_uart->uart);
}
static void bsp_uart_tx_begin_call_back(bsp_uart_t *p_uart)
{
/* RS485切换到发送模式 */
if(p_uart == &com_uart4)
{
RS485_1_TX;
}
else if(p_uart == &com_uart2)
{
RS485_2_TX;
}
else if(p_uart == &com_uart3)
{
RS485_3_TX;
}
else if(p_uart == &com_uart6)
{
RS485_4_TX;
}
}
static void bsp_uart_tx_end_call_back(bsp_uart_t *p_uart)
{
/* RS485切换到发送模式 */
if(p_uart == &com_uart4)
{
RS485_1_RX;
}
else if(p_uart == &com_uart2)
{
RS485_2_RX;
}
else if(p_uart == &com_uart3)
{
RS485_3_RX;
}
else if(p_uart == &com_uart6)
{
RS485_4_RX;
}
}
/******************************************
* 函数: bsp_uart_dma_send
* 功能: DMA发送函数
* 参数: p_uart - 指向UART结构体的指针
* p_data - 要发送的数据指针
* len - 要发送的数据长度
* 返回: 无
* 描述: 使用DMA发送数据,带有超时检测
*******************************************/
static void bsp_uart_dma_send(bsp_uart_t *p_uart, u8 *p_data, u16 len)
{
u32 tick_start, tick;
p_uart->tx_dma_complete_flag = 0;
/* 如果请求发送的长度大于缓冲区长度,则截断 */
if(p_uart->tx_dma_len < len)
len = p_uart->tx_dma_len;
/* 拷贝数据到发送缓冲区 */
memcpy(p_uart->tx_addr, p_data, len);
/* 启动DMA发送 */
HAL_UART_Transmit_DMA(p_uart->uart, p_uart->tx_addr, len);
/* 等待发送完成,带超时检测 */
tick_start = HAL_GetTick();
while(!p_uart->tx_dma_complete_flag)
{
tick = HAL_GetTick();
if((tick - tick_start) > 200) /* 200ms超时 */
{
p_uart->tx_dma_complete_flag = 1;
break;
}
}
}
/******************************************
* 函数: bsp_uart_send
* 功能: UART发送函数
* 参数: p_uart - 指向UART结构体的指针
* p_data - 要发送的数据指针
* len - 要发送的数据长度
* 返回: 无
* 描述: 大数据量发送函数,支持分块发送
*******************************************/
static void bsp_uart_send(bsp_uart_t *p_uart, u8 *p_data, u16 len)
{
u16 i, send_num;
bsp_uart_tx_begin_call_back(p_uart);
/* 计算需要发送的次数 */
send_num = len / p_uart->tx_dma_len;
/* 分块发送数据 */
for(i = 0; i < send_num; i++)
{
bsp_uart_dma_send(p_uart, &p_data[p_uart->tx_dma_len * i], p_uart->tx_dma_len);
}
/* 发送剩余数据 */
len -= p_uart->tx_dma_len * i;
if(0 != len)
{
bsp_uart_dma_send(p_uart, &p_data[p_uart->tx_dma_len * i], len);
}
bsp_uart_tx_end_call_back(p_uart);
}
/******************************************
* 函数: bsp_uart_tx_dma_tc_int
* 功能: DMA发送完成中断处理
* 参数: p_uart - 指向UART结构体的指针
* 返回: 无
* 描述: 在DMA发送完成中断中调用,设置发送完成标志
*******************************************/
static void bsp_uart_tx_dma_tc_int(bsp_uart_t *p_uart)
{
p_uart->tx_dma_complete_flag = 1;
}
/******************************************
* 函数: bsp_uart_rx_idle_int
* 功能: 空闲中断处理
* 参数: p_uart - 指向UART结构体的指针
* 返回: 无
* 描述: 处理UART空闲中断,将接收到的数据存入队列
*******************************************/
static void bsp_uart_rx_idle_int(bsp_uart_t *p_uart)
{
u16 rx_length, i;
/* 停止接收 */
HAL_UART_DMAStop(p_uart->uart);
/* 计算接收到的数据长度 */
rx_length = p_uart->rx_dma_len - __HAL_DMA_GET_COUNTER(p_uart->rx_dma);
/* 如果长度为0,直接返回 */
if (rx_length == 0)
{
return;
}
/* 将接收到的数据存入队列 */
for (i = 0; i < rx_length; i++)
{
queue_push_back(p_uart->rx_queue, (void *)&p_uart->rx_addr[i]);
}
/* 开始接收超时计时 */
bsp_uart_rx_time_start(p_uart);
/* 重新启动接收 */
HAL_UARTEx_ReceiveToIdle_DMA(p_uart->uart, p_uart->rx_addr, p_uart->rx_dma_len);
}
/******************************************
* 函数: bsp_uart_rx_time_increment
* 功能: 接收超时时间递增
* 参数: p_uart - 指向UART结构体的指针
* time - 增加的时间值
* 返回: 无
* 描述: 在中断中调用,递增接收超时计数器
*******************************************/
static void bsp_uart_rx_time_increment(bsp_uart_t *p_uart, u16 time)
{
/* 如果已经开始计数,则增加时间 */
if(1 == p_uart->rx_start_flag)
{
p_uart->rx_time_count += time;
}
}
/******************************************
* 函数: bsp_uart_rx_time_start
* 功能: 启动接收超时计时
* 参数: p_uart - 指向UART结构体的指针
* 返回: 无
* 描述: 开始接收超时计数
*******************************************/
static void bsp_uart_rx_time_start(bsp_uart_t *p_uart)
{
p_uart->rx_start_flag = 1;
p_uart->rx_time_count = 0;
}
/******************************************
* 函数: bsp_uart_rx_time_stop
* 功能: 停止接收超时计时
* 参数: p_uart - 指向UART结构体的指针
* 返回: 无
* 描述: 停止接收超时计数
*******************************************/
static void bsp_uart_rx_time_stop(bsp_uart_t *p_uart)
{
p_uart->rx_start_flag = 0;
p_uart->rx_time_count = 0;
}
/******************************************
* 函数: bsp_uart_rx_task
* 功能: UART接收任务
* 参数: p_uart - 指向UART结构体的指针
* 返回: 无
* 描述: 检查接收超时,处理接收到的数据帧
*******************************************/
static void bsp_uart_rx_task(bsp_uart_t *p_uart)
{
/* 检查是否超时,接收到一帧数据 */
if(p_uart->rx_time_over < p_uart->rx_time_count)
{
/* 获取队列中数据长度 */
p_uart->rx_len = queue_size(p_uart->rx_queue);
/* 停止计时 */
bsp_uart_rx_time_stop(p_uart);
/* 检查数据长度是否有效 */
if(p_uart->rx_len <= p_uart->rx_dma_len && (0 != p_uart->rx_len))
{
/* 如果数据长度超过临时缓冲区大小,则清空队列 */
if(RX_TEMP_BUFF_NUM < p_uart->rx_len)
{
queue_clear(p_uart->rx_queue);
}
else
{
/* 从队列中取出数据到临时缓冲区 */
for(u16 i = 0; i < p_uart->rx_len; i++)
{
queue_pop(p_uart->rx_queue, &rx_temp_buff[i]);
}
/* 如果有数据解析函数,则调用解析函数 */
if(NULL != p_uart->rx_data_analysis)
{
p_uart->rx_data_analysis(rx_temp_buff, p_uart->rx_len, p_uart);
}
if(p_uart == &com_uart6)
{
p_uart->send(p_uart, rx_temp_buff, p_uart->rx_len);
}
}
}
}
}
// 错误回调函数中处理ORE
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
bsp_uart_t *p_uart = NULL;
if (huart->Instance == USART1)
{
p_uart = &com_uart1;
}
else if (huart->Instance == USART2)
{
p_uart = &com_uart2;
}
else if (huart->Instance == USART3)
{
p_uart = &com_uart3;
}
else if (huart->Instance == UART4)
{
p_uart = &com_uart4;
}
else if (huart->Instance == USART6)
{
p_uart = &com_uart6;
}
// 检查具体错误类型
if(huart->ErrorCode & HAL_UART_ERROR_NE)
{
// 处理噪声错误
__HAL_UART_CLEAR_NEFLAG(huart);
}
if(huart->ErrorCode & HAL_UART_ERROR_FE)
{
// 处理帧错误
__HAL_UART_CLEAR_FEFLAG(huart);
}
// 其他错误处理...
if (__HAL_UART_GET_FLAG(huart, UART_FLAG_ORE) != RESET)
{
__HAL_UART_CLEAR_OREFLAG(huart); // 清除ORE标志
}
if (__HAL_UART_GET_FLAG(huart, UART_FLAG_FE) != RESET)
{
__HAL_UART_CLEAR_FEFLAG(huart); // 清除ORE标志
}
//
if(p_uart != NULL)
{
// HAL_UART_DeInit(huart);
// HAL_UART_Init(huart);
// HAL_UART_DMAStop(p_Uart->Uart);
HAL_UARTEx_ReceiveToIdle_DMA(p_uart->uart, p_uart->rx_addr, p_uart->rx_dma_len);
}
}
// 实现空闲中断回调
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
if (huart->Instance == USART1)
{
bsp_uart_rx_idle_int(&com_uart1);
}
else if (huart->Instance == USART2)
{
bsp_uart_rx_idle_int(&com_uart2);
}
else if (huart->Instance == USART3)
{
bsp_uart_rx_idle_int(&com_uart3);
}
else if (huart->Instance == UART4)
{
bsp_uart_rx_idle_int(&com_uart4);
}
else if (huart->Instance == USART6)
{
bsp_uart_rx_idle_int(&com_uart6);
}
}
/* 串口接收完成回调函数 - 处理空闲中断 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
// if (__HAL_UART_GET_FLAG(huart, UART_FLAG_IDLE))
// {
// __HAL_UART_CLEAR_IDLEFLAG(huart);
// if (huart->Instance == USART1)
// {
// bsp_Uart_Rx_IdleInt(&COM_Uart1);
// }
// else if (huart->Instance == USART2)
// {
// bsp_Uart_Rx_IdleInt(&COM_Uart2);
// }
// else if (huart->Instance == UART4)
// {
// bsp_Uart_Rx_IdleInt(&COM_Uart4);
// }
// }
}
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart->Instance == USART1)
{
bsp_uart_tx_dma_tc_int(&com_uart1);
}
else if (huart->Instance == USART2)
{
bsp_uart_tx_dma_tc_int(&com_uart2);
}
else if (huart->Instance == USART3)
{
bsp_uart_tx_dma_tc_int(&com_uart3);
}
else if (huart->Instance == UART4)
{
bsp_uart_tx_dma_tc_int(&com_uart2);
}
else if (huart->Instance == USART6)
{
bsp_uart_tx_dma_tc_int(&com_uart6);
}
}
+85
View File
@@ -0,0 +1,85 @@
#ifndef _BSP_UART_H_
#define _BSP_UART_H_
#include "main.h"
#include "algo_queue.h"
/******************************************
* 结构体: bsp_uart_t
* 功能: UART控制结构体
* 描述: 包含UART的所有配置和状态信息
*******************************************/
typedef struct bsp_uart_t bsp_uart_t;
/* 类型重定义 */
#define usart_type UART_HandleTypeDef
#define dma_type DMA_HandleTypeDef
#define BSP_UART_BAUD_RATE_4800 (4800)
#define BSP_UART_BAUD_RATE_9600 (9600)
#define BSP_UART_BAUD_RATE_19200 (19200)
#define BSP_UART_BAUD_RATE_57600 (57600)
#define BSP_UART_BAUD_RATE_115200 (57600)
/******************************************
* 结构体: bsp_uart_relay_t
* 功能: UART转发结构体
* 描述: 用于配置UART数据转发功能
*******************************************/
typedef struct
{
u8 flag; /* 串口转发标志位 */
bsp_uart_t *uart; /* 转发出去的串口指针 */
u16 time_out; /* 转发超时时间 */
} bsp_uart_relay_t;
struct bsp_uart_t
{
queue rx_queue; /* 数据接收队列 */
usart_type *uart; /* 串口句柄指针 */
dma_type *tx_dma; /* 发送DMA句柄 */
dma_type *rx_dma; /* 接收DMA句柄 */
u8 tx_dma_ch; /* 发送DMA通道号 */
u8 rx_dma_ch; /* 接收DMA通道号 */
vu8 tx_dma_complete_flag; /* DMA接收完成标志位 */
u8 *tx_addr; /* DMA发送缓冲区地址 */
u8 *rx_addr; /* DMA接收缓冲区地址 */
u16 tx_dma_len; /* DMA发送缓冲区长度 */
u16 rx_dma_len; /* DMA接收缓冲区长度 */
u16 rx_len; /* 接收到的数据长度 */
u16 rx_time_count; /* 超时计数 */
u16 rx_time_over; /* 超时时间 */
u8 rx_start_flag; /* 开始超时计数标志位 */
bsp_uart_relay_t relay; /* 串口转发配置 */
struct
{
void (*baud_rate)(bsp_uart_t *,u16);
}set;
void (*init)(bsp_uart_t *); /* 初始化函数指针 */
void (*send)(bsp_uart_t *, u8 *, u16); /* 串口发送函数指针 */
void (*tx_dma_tc_int)(bsp_uart_t *); /* DMA发送完成中断处理函数指针 */
void (*rx_idle_int)(bsp_uart_t *); /* 空闲中断处理函数指针 */
void (*rx_time_increment_int)(bsp_uart_t *, u16); /* 中断计数函数指针 */
void (*rx_data_analysis)(u8 *, u16, void *); /* 数据解析函数指针 */
void (*rx_task)(bsp_uart_t *); /* 串口接收任务函数指针 */
};
/* 声明外部变量 */
extern bsp_uart_t com_uart1;
extern bsp_uart_t com_uart2; /*COM2*/
extern bsp_uart_t com_uart3; /*COM3*/
extern bsp_uart_t com_uart4; /*COM1*/
extern bsp_uart_t com_uart6; /*COM6*/
#endif
+242
View File
@@ -0,0 +1,242 @@
#include "bsp_w25q.h"
#include "spi.h"
#include "main.h"
/* spi flash 片选引脚 - pb12 */
#define W25Q32_CS_LOW() HAL_GPIO_WritePin(SPI2_CS_GPIO_Port, SPI2_CS_Pin, GPIO_PIN_RESET)
#define W25Q32_CS_HIGH() HAL_GPIO_WritePin(SPI2_CS_GPIO_Port, SPI2_CS_Pin, GPIO_PIN_SET)
/* spi 传输函数 */
static void w25q32_spi_transmit(uint8_t *data, uint16_t size) {
HAL_SPI_Transmit(&hspi2, data, size, HAL_MAX_DELAY);
}
static void w25q32_spi_receive(uint8_t *data, uint16_t size) {
HAL_SPI_Receive(&hspi2, data, size, HAL_MAX_DELAY);
}
static uint8_t w25q32_spi_transmit_receive(uint8_t data) {
uint8_t rx_data;
HAL_SPI_TransmitReceive(&hspi2, &data, &rx_data, 1, HAL_MAX_DELAY);
return rx_data;
}
/* 内部函数声明 */
static void w25q32_init(void);
static void w25q32_read(uint32_t addr, uint8_t *data, uint32_t len);
static void w25q32_write(uint32_t addr, uint8_t *data, uint32_t len);
static void w25q32_chip_erase(void);
static void w25q32_write_enable(void);
static void w25q32_write_disable(void);
static uint8_t w25q32_read_status_reg(void);
static void w25q32_wait_for_write_end(void);
static void w25q32_block_erase(uint32_t block_addr);
static void w25q32_page_write(uint32_t addr, uint8_t *data, uint16_t len);
static uint8_t w25q32_read_id(void);
static void w25q32_power_down(void);
static void w25q32_wake_up(void);
/* w25q32 对象实例 */
w25q32_t w25q32 = {
.init = w25q32_init,
.read = w25q32_read,
.write = w25q32_write,
.chip_erase = w25q32_chip_erase,
.sector_erase = w25q32_sector_erase,
};
/* 初始化函数 */
static void w25q32_init(void) {
W25Q32_CS_HIGH(); /* 初始时片选拉高 */
w25q32_wake_up(); /* 唤醒芯片 */
}
/* 读取芯片id */
static uint8_t w25q32_read_id(void) {
uint8_t id = 0;
uint8_t cmd = W25Q32_JEDEC_ID;
W25Q32_CS_LOW();
w25q32_spi_transmit(&cmd, 1);
w25q32_spi_receive(&id, 1); /* 忽略前两个字节 */
w25q32_spi_receive(&id, 1);
w25q32_spi_receive(&id, 1); /* 设备id在第三个字节 */
W25Q32_CS_HIGH();
return id;
}
/* 写使能 */
static void w25q32_write_enable(void) {
uint8_t cmd = W25Q32_WRITE_ENABLE;
W25Q32_CS_LOW();
w25q32_spi_transmit(&cmd, 1);
W25Q32_CS_HIGH();
}
/* 写禁止 */
static void w25q32_write_disable(void) {
uint8_t cmd = W25Q32_WRITE_DISABLE;
W25Q32_CS_LOW();
w25q32_spi_transmit(&cmd, 1);
W25Q32_CS_HIGH();
}
/* 读取状态寄存器 */
static uint8_t w25q32_read_status_reg(void) {
uint8_t status;
uint8_t cmd = W25Q32_READ_STATUS_REG1;
W25Q32_CS_LOW();
w25q32_spi_transmit(&cmd, 1);
status = w25q32_spi_transmit_receive(0x00);
W25Q32_CS_HIGH();
return status;
}
/* 等待写入完成 */
static void w25q32_wait_for_write_end(void) {
while (w25q32_read_status_reg() & W25Q32_STATUS_BUSY) {
/* 可添加延时或看门狗喂狗 */
}
}
/* 扇区擦除 (4kb) */
void w25q32_sector_erase(uint32_t sector_addr)
{
uint8_t cmd[4];
/* 确保地址是4k对齐 */
sector_addr &= ~(W25Q32_SECTOR_SIZE - 1);
w25q32_write_enable();
cmd[0] = W25Q32_SECTOR_ERASE;
cmd[1] = (sector_addr >> 16) & 0xFF;
cmd[2] = (sector_addr >> 8) & 0xFF;
cmd[3] = sector_addr & 0xFF;
W25Q32_CS_LOW();
w25q32_spi_transmit(cmd, 4);
W25Q32_CS_HIGH();
w25q32_wait_for_write_end();
}
/* 块擦除 (64kb) */
static void w25q32_block_erase(uint32_t block_addr) {
uint8_t cmd[4];
/* 确保地址是64k对齐 */
block_addr &= ~(W25Q32_BLOCK_SIZE - 1);
w25q32_write_enable();
cmd[0] = W25Q32_BLOCK_ERASE_64K;
cmd[1] = (block_addr >> 16) & 0xFF;
cmd[2] = (block_addr >> 8) & 0xFF;
cmd[3] = block_addr & 0xFF;
W25Q32_CS_LOW();
w25q32_spi_transmit(cmd, 4);
W25Q32_CS_HIGH();
w25q32_wait_for_write_end();
}
/* 整片擦除 */
static void w25q32_chip_erase(void) {
uint8_t cmd = W25Q32_CHIP_ERASE;
w25q32_write_enable();
W25Q32_CS_LOW();
w25q32_spi_transmit(&cmd, 1);
W25Q32_CS_HIGH();
w25q32_wait_for_write_end();
}
/* 页写入 (最大256字节) */
static void w25q32_page_write(uint32_t addr, uint8_t *data, uint16_t len) {
uint8_t cmd[4];
if (len > W25Q32_PAGE_SIZE) {
len = W25Q32_PAGE_SIZE;
}
w25q32_write_enable();
cmd[0] = W25Q32_PAGE_PROGRAM;
cmd[1] = (addr >> 16) & 0xFF;
cmd[2] = (addr >> 8) & 0xFF;
cmd[3] = addr & 0xFF;
W25Q32_CS_LOW();
w25q32_spi_transmit(cmd, 4);
w25q32_spi_transmit(data, len);
W25Q32_CS_HIGH();
w25q32_wait_for_write_end();
}
/* 任意长度写入 */
static void w25q32_write(uint32_t addr, uint8_t *data, uint32_t len) {
uint32_t page_remaining;
uint32_t offset = 0;
while (len > 0) {
/* 计算当前页剩余字节数 */
page_remaining = W25Q32_PAGE_SIZE - (addr % W25Q32_PAGE_SIZE);
/* 本次写入的长度 */
uint32_t write_len = (len < page_remaining) ? len : page_remaining;
/* 写入一页数据 */
w25q32_page_write(addr, &data[offset], write_len);
/* 更新地址和偏移 */
addr += write_len;
offset += write_len;
len -= write_len;
}
}
/* 读取数据 */
static void w25q32_read(uint32_t addr, uint8_t *data, uint32_t len) {
uint8_t cmd[4];
cmd[0] = W25Q32_READ_DATA;
cmd[1] = (addr >> 16) & 0xFF;
cmd[2] = (addr >> 8) & 0xFF;
cmd[3] = addr & 0xFF;
W25Q32_CS_LOW();
w25q32_spi_transmit(cmd, 4);
w25q32_spi_receive(data, len);
W25Q32_CS_HIGH();
}
/* 进入掉电模式 */
static void w25q32_power_down(void) {
uint8_t cmd = W25Q32_POWER_DOWN;
W25Q32_CS_LOW();
w25q32_spi_transmit(&cmd, 1);
W25Q32_CS_HIGH();
}
/* 唤醒芯片 */
static void w25q32_wake_up(void) {
uint8_t cmd = W25Q32_RELEASE_POWER_DOWN;
W25Q32_CS_LOW();
w25q32_spi_transmit(&cmd, 1);
W25Q32_CS_HIGH();
HAL_Delay(5); /* 等待芯片唤醒 */
}
+64
View File
@@ -0,0 +1,64 @@
#ifndef __BSP_W25Q_H__
#define __BSP_W25Q_H__
#include "main.h"
/* w25q32jvssiq 容量参数 */
#define W25Q32_FLASH_SIZE (0x400000UL) /* 4mb = 32mb */
#define W25Q32_PAGE_SIZE (256) /* 页大小 */
#define W25Q32_SECTOR_SIZE (4096) /* 扇区大小 */
#define W25Q32_BLOCK_SIZE (65536) /* 块大小 */
/* w25q32jvssiq 命令字 */
#define W25Q32_WRITE_ENABLE 0x06
#define W25Q32_WRITE_DISABLE 0x04
#define W25Q32_READ_STATUS_REG1 0x05
#define W25Q32_WRITE_STATUS_REG 0x01
#define W25Q32_READ_DATA 0x03
#define W25Q32_FAST_READ 0x0B
#define W25Q32_PAGE_PROGRAM 0x02
#define W25Q32_SECTOR_ERASE 0x20
#define W25Q32_BLOCK_ERASE_32K 0x52
#define W25Q32_BLOCK_ERASE_64K 0xD8
#define W25Q32_CHIP_ERASE 0xC7
#define W25Q32_POWER_DOWN 0xB9
#define W25Q32_RELEASE_POWER_DOWN 0xAB
#define W25Q32_DEVICE_ID 0xAB
#define W25Q32_MANUFACTURER_ID 0x90
#define W25Q32_JEDEC_ID 0x9F
void w25q32_sector_erase(uint32_t sector_addr);
/* 状态寄存器位 */
#define W25Q32_STATUS_BUSY (1 << 0)
#define W25Q32_STATUS_WRITE_EN (1 << 1)
/* flash 存储区域 */
#define W25Q32_USER_DATA_ADDR 0x000000 /* 用户数据存储起始地址 */
#define W25Q32_USER_DATA_SIZE 0x100000 /* 大约1mb空间用于用户数据 */
#define W25Q32_DEVICE_INFO_ADDR (0x001000) /* 设备信息存储地址 - 扇区1,4K对齐 */
#define DEVICE_INFO_STORAGE_SIZE (APP_LEAKAGE_SUB_DEVICE_NUM * sizeof(app_leakage_sub_device_flash_data_t)) /*设备信息存储大小*/
/* 历史报警存储地址和大小 */
#define W25Q32_HISTORY_ALARM_METADATA_ADDR 0x002000 /* 历史报警元数据存储地址 - 扇区2 */
#define W25Q32_HISTORY_ALARM_DATA_ADDR 0x003000 /* 历史报警数据存储地址 - 从扇区3开始 */
#define HISTORY_ALARM_RECORD_SIZE (sizeof(app_leakage_history_alarm_t)) /* 每条记录大小 */
#define HISTORY_ALARM_RECORDS_PER_SECTOR (W25Q32_SECTOR_SIZE / HISTORY_ALARM_RECORD_SIZE) /* 每扇区记录数 */
#define MAX_HISTORY_ALARM_RECORDS (1000) /* 最大历史报警记录数 */
#define HISTORY_ALARM_SECTORS_NEEDED ((MAX_HISTORY_ALARM_RECORDS * HISTORY_ALARM_RECORD_SIZE + W25Q32_SECTOR_SIZE - 1) / W25Q32_SECTOR_SIZE)
/* w25q32 对象结构体 */
typedef struct {
void (*init)(void);
void (*read)(uint32_t addr, uint8_t *data, uint32_t len);
void (*write)(uint32_t addr, uint8_t *data, uint32_t len);
void (*chip_erase)(void);
void (*sector_erase)(uint32_t sector_addr);
} w25q32_t;
/* 全局对象 */
extern w25q32_t w25q32;
#endif /* __BSP_W25Q_H__ */
+104
View File
@@ -0,0 +1,104 @@
#ifndef _SYS_H_
#define _SYS_H_
#include "stm32f4xx.h"
//定义一些常用的数据类型短关键字
typedef int32_t s32;
typedef int16_t s16;
typedef int8_t s8;
typedef const int32_t sc32;
typedef const int16_t sc16;
typedef const int8_t sc8;
typedef __IO int32_t vs32;
typedef __IO int16_t vs16;
typedef __IO int8_t vs8;
typedef __I int32_t vsc32;
typedef __I int16_t vsc16;
typedef __I int8_t vsc8;
typedef uint32_t u32;
typedef uint16_t u16;
typedef uint8_t u8;
typedef const uint32_t uc32;
typedef const uint16_t uc16;
typedef const uint8_t uc8;
typedef __IO uint32_t vu32;
typedef __IO uint16_t vu16;
typedef __IO uint8_t vu8;
typedef __I uint32_t vuc32;
typedef __I uint16_t vuc16;
typedef __I uint8_t vuc8;
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2))
#define MEM_ADDR(addr) *((volatile unsigned long *)(addr))
#define BIT_ADDR(addr, bitnum) MEM_ADDR(BITBAND(addr, bitnum))
//IO口地址映射
#define GPIOA_ODR_Addr (GPIOA_BASE+12) //0x4001080C
#define GPIOB_ODR_Addr (GPIOB_BASE+12) //0x40010C0C
#define GPIOC_ODR_Addr (GPIOC_BASE+12) //0x4001100C
#define GPIOD_ODR_Addr (GPIOD_BASE+12) //0x4001140C
#define GPIOE_ODR_Addr (GPIOE_BASE+12) //0x4001180C
#define GPIOF_ODR_Addr (GPIOF_BASE+12) //0x40011A0C
#define GPIOG_ODR_Addr (GPIOG_BASE+12) //0x40011E0C
#define GPIOA_IDR_Addr (GPIOA_BASE+8) //0x40010808
#define GPIOB_IDR_Addr (GPIOB_BASE+8) //0x40010C08
#define GPIOC_IDR_Addr (GPIOC_BASE+8) //0x40011008
#define GPIOD_IDR_Addr (GPIOD_BASE+8) //0x40011408
#define GPIOE_IDR_Addr (GPIOE_BASE+8) //0x40011808
#define GPIOF_IDR_Addr (GPIOF_BASE+8) //0x40011A08
#define GPIOG_IDR_Addr (GPIOG_BASE+8) //0x40011E08
//IO口操作,只对单一的IO口!
//确保n的值小于16!
#define PAout(n) BIT_ADDR(GPIOA_ODR_Addr,n) //输出
#define PAin(n) BIT_ADDR(GPIOA_IDR_Addr,n) //输入
#define PBout(n) BIT_ADDR(GPIOB_ODR_Addr,n) //输出
#define PBin(n) BIT_ADDR(GPIOB_IDR_Addr,n) //输入
#define PCout(n) BIT_ADDR(GPIOC_ODR_Addr,n) //输出
#define PCin(n) BIT_ADDR(GPIOC_IDR_Addr,n) //输入
#define PDout(n) BIT_ADDR(GPIOD_ODR_Addr,n) //输出
#define PDin(n) BIT_ADDR(GPIOD_IDR_Addr,n) //输入
#define PEout(n) BIT_ADDR(GPIOE_ODR_Addr,n) //输出
#define PEin(n) BIT_ADDR(GPIOE_IDR_Addr,n) //输入
#define PFout(n) BIT_ADDR(GPIOF_ODR_Addr,n) //输出
#define PFin(n) BIT_ADDR(GPIOF_IDR_Addr,n) //输入
#define PGout(n) BIT_ADDR(GPIOG_ODR_Addr,n) //输出
#define PGin(n) BIT_ADDR(GPIOG_IDR_Addr,n) //输入
/////////////////////////////////////////////////////////////////
//Ex_NVIC_Config专用定义
#define GPIO_A 0
#define GPIO_B 1
#define GPIO_C 2
#define GPIO_D 3
#define GPIO_E 4
#define GPIO_F 5
#define GPIO_G 6
#define FTIR 1 //下降沿触发
#define RTIR 2 //上升沿触发
#endif
File diff suppressed because it is too large Load Diff
+26
View File
@@ -0,0 +1,26 @@
#ifndef _GUI_TJC_HMI_H_
#define _GUI_TJC_HMI_H_
#include "main.h"
/*页码*/
typedef struct
{
u8 main_index;/*主界面页码*/
u8 deliniter_main_index;/*主界面选中区域的全局索引*/
u8 real_alarm_index;/*实时报警界面页码*/
u8 detail_main_index;/*区域详情界面页码*/
u8 device_config_index;/*设备配置界面页码*/
u8 history_alarm_index;/*历史报警界面页码*/
}gui_tjc_hmi_page_t;
typedef struct
{
gui_tjc_hmi_page_t page;
u8 password[4];
void (*init)(void);
}gui_tjc_hmi_t;
extern gui_tjc_hmi_t tjc_hmi;
#endif
@@ -0,0 +1,296 @@
#include "proto_modbus_lib.h"
#include "stdio.h"
#include "string.h"
#include "bsp_Uart.h"
/**************************************************
*名称: modbus_lib_crc16
*功能: modbus crc16校验
*参数: p_data -- 校验数据指针
* len -- 数据长度
*返回: 校验结果(小端序)
**************************************************/
u16 modbus_lib_crc16(u8 *p_data, u16 len)
{
u16 crc16 = 0xFFFF;
u16 i, j;
for (i = 0; i < len; i++) {
crc16 ^= p_data[i];
for (j = 0; j < 8; j++) {
if (crc16 & 0x0001) {
crc16 >>= 1;
crc16 ^= 0xA001;
} else {
crc16 >>= 1;
}
}
}
return crc16;
}
/************************************
* 函数: Float2u16
* 功能: 提取浮点数的高16或低16位
* 参数: float_data : 要转换的浮点数
h_l : 返回高16位还是低16位
* 返回: 返回对应的高16位还是低16位
* 描述: 无
******************************************/
u16 float_to_u16(float float_data,unsigned char h_l)
{
u16 temp = 0XFFFF;
if(h_l == U16_DATA_L)
{
temp = *((u32 *)&float_data) & 0x0000ffff;
}
else if(h_l == U16_DATA_H)
{
temp = ((*((u32 *)&float_data)) >> 16) & 0x0000ffff;
}
return temp;
}
/******************************************
* 函数: u32TOu16
* 功能: 提取u32的高16或低16位
* 参数: u32_data : 要转换的u32
h_l : 返回高16位还是低16位
* 返回: 返回对应的高16位还是低16位
* 描述: 无
******************************************/
u16 u32_to_u16(u32 u32_data,unsigned char h_l)
{
u16 temp = 0XFFFF;
if(h_l == U16_DATA_L)
{
temp = u32_data & 0x0000ffff;
}
else if(h_l == U16_DATA_H)
{
temp = (u32_data >> 16) & 0x0000ffff;
}
return temp;
}
void u32_to_u8(u32 u32_data,u8 *p_data,u8 endian)
{
if(BIG_ENDIAN == endian)
{
for(u8 i = 0;i < 4;i++)
{
p_data[i] = (u32_data >> (8 * (3 - i))) & 0xff;
}
}
else if(LITTLE_ENDIAN == endian)
{
for(u8 i = 0;i < 4;i++)
{
p_data[i] = (u32_data >> (8 * i)) & 0xff;
}
}
}
void u16_to_u8(u16 u16_data,u8 *p_data,u8 endian)
{
if(BIG_ENDIAN == endian)
{
for(u8 i = 0;i < 2;i++)
{
p_data[i] = (u16_data >> (8 * (1 - i))) & 0xff;
}
}
else if(LITTLE_ENDIAN == endian)
{
for(u8 i = 0;i < 2;i++)
{
p_data[i] = (u16_data >> (8 * i)) & 0xff;
}
}
}
float u32_to_float(u32 u32_data,unsigned char h_l)
{
float temp = 0;
temp = *((float *)&u32_data);
return temp;
}
/*将u8_endian端序的p_u8data转换为单片机对应的小端序*/
u32 u8_to_u32(u8 *p_u8data,unsigned char u8_endian)
{
u32 temp = 0;
if(BIG_ENDIAN == u8_endian)
{
for(u8 i = 0;i < 4;i++)
{
temp |= p_u8data[i] << ((3 - i) * 8);
}
}
else if(LITTLE_ENDIAN == u8_endian)
{
for(u8 i = 0;i < 4;i++)
{
temp |= p_u8data[i] << (i * 8);
}
}
return temp;
}
/*将u8_endian端序的p_u8data转换为单片机对应的小端序*/
u16 u8_to_u16(u8 *p_u8data,unsigned char u8_endian)
{
u32 temp = 0;
if(BIG_ENDIAN == u8_endian)
{
for(u8 i = 0;i < 2;i++)
{
temp |= p_u8data[i] << ((1 - i) * 8);
}
}
else if(LITTLE_ENDIAN == u8_endian)
{
for(u8 i = 0;i < 2;i++)
{
temp |= p_u8data[i] << (i * 8);
}
}
return temp;
}
/*字节端序转换*/
u32 u32_endian_conv(u32 data)
{
u32 temp = 0;
temp = (((data >> 0 ) & 0xff) << 24)
| (((data >> 8 ) & 0xff) << 16)
| (((data >> 16) & 0xff) << 8 )
| (((data >> 24) & 0xff) << 0 );
return temp;
}
/*字节端序转换*/
u16 u16_endian_conv(u16 data)
{
u16 temp = 0;
temp = (((data >> 0) & 0xff) << 8)
| (((data >> 8) & 0xff) << 0);
return temp;
}
/******************************************
* 函数: ModbusReaddata
* 功能: MODBUS读数据
* 参数: Id :MODBUS从机地址
* addr :写数据的起始地址
* Num :写的寄存器数量
* send :串口发送函数
* 返回: 无
* 描述: 无
******************************************/
void modbus_lib_data_read(u8 id,u16 addr,u16 num,void (*send)(u8 *,u16 ))
{
u8 tx[8];
u16 crc16;
tx[0] = id;
tx[1] = 0x03;//0x03;
tx[2] = (addr >> 8) & 0xff;
tx[3] = addr & 0xff;
tx[4] = (num >> 8) & 0xff;
tx[5] = num & 0xff;
crc16 = modbus_lib_crc16(tx,6);
tx[6] = crc16 & 0xff;
tx[7] = (crc16 >> 8) & 0xff;
send(tx,8);
}
/******************************************
* 函数: modbus_multiple_data_write
* 功能: MODBUS写数据
* 参数: Id :MODBUS从机地址
* addr :写数据的起始地址
* Num :写的寄存器数量
* data :写的数据
* send :串口发送函数
* 返回: 无
* 描述: 无
******************************************/
void modbus_lib_multiple_data_write(u8 id,u16 addr,u16 Num,u16 *data,void (*send)(u8 *,u16 ))
{
u8 tx[50];
u16 crc16,i;
tx[0] = id;
tx[1] = 0x10;
tx[2] = (addr >> 8) & 0xff;
tx[3] = addr & 0xff;
tx[4] = (Num >> 8) & 0xff;
tx[5] = Num & 0xff;
tx[6] = Num * 2;
for(i = 0;i < tx[6]/2;i++)
{
tx[7 + 2 * i] = (data[i] >> 8) & 0xff;
tx[8 + 2 * i] = data[i] & 0xff;
}
crc16 = modbus_lib_crc16(tx,7 + 2 * i);
tx[7 + 2 * i] = crc16 & 0xff;
tx[8 + 2 * i] = (crc16 >> 8) & 0xff;
send(tx,9 + 2 * i);
}
void modbus_lib_only_data_write(u8 id,u16 addr,u16 value,void (*send)(u8 *,u16 ))
{
u8 tx[8];
u16 crc16;
tx[0] = id;
tx[1] = 0x06;
tx[2] = (addr >> 8) & 0xff;
tx[3] = addr & 0xff;
tx[4] = (value >> 8) & 0xff;
tx[5] = value & 0xff;
crc16 = modbus_lib_crc16(tx,6);
tx[6] = crc16 & 0xff;
tx[7] = (crc16 >> 8) & 0xff;
send(tx,8);
}
//01 10 00 02 00 01 02 12 34 CRC
//id Func Startaddress RegNumber wdataaddress
u8 modbus_lib_analysis(modbus_analysis_data_t *p_modbus, u8 *p_data, u16 len)
{
u16 crc16;
u16 u16_temp;
if(NULL == p_modbus) return 0;
if(len < 8) return 0;
crc16 = modbus_lib_crc16(p_data, len-2);
u16_temp = *(p_data+len-1);
u16_temp <<= 8;
u16_temp |= *(p_data+len-2);
if(u16_temp != crc16) return 0;
p_modbus->id = *p_data;
p_modbus->func = *(p_data+1);
p_modbus->start_addr = (*(p_data+2))<<8;
p_modbus->start_addr |= *(p_data+3);
/*单独写一个寄存器*/
if(0x06 == p_modbus->func)
{
p_modbus->write_data_addr = p_data+4;
}
else if(0x10 == p_modbus->func) /*写多个寄存器*/
{
p_modbus->reg_number = (*(p_data+4))<<8;
p_modbus->reg_number |= *(p_data+5);
p_modbus->write_data_addr = p_data+7;
}
else
{
p_modbus->reg_number = (*(p_data+4))<<8;
p_modbus->reg_number |= *(p_data+5);
}
return 1;
}
@@ -0,0 +1,67 @@
#ifndef _PROTO_MODBUS_LIB_H_
#define _PROTO_MODBUS_LIB_H_
#include "main.h"
#define MODBUS_DEFAULT_ID (0x01)
#define MODBUS_SENDBUF_LEN (2048U)
#define U16_DATA_L (0)//低16位
#define U16_DATA_H (1)//高16位
#define BIG_ENDIAN (0)//大端序
#define LITTLE_ENDIAN (1)//小端序
typedef struct {
u8 send_buffer[MODBUS_SENDBUF_LEN];
u16 len;
}modbus_communication_send_buf_t;
typedef struct
{
u8 id; /*ModbusID*/
u8 func; /*功能号*/
u16 start_addr; /*起始地址*/
u16 reg_number; /*寄存器数量*/
u8 *write_data_addr; /*写入寄存器数据地址*/
}modbus_analysis_data_t;
typedef enum
{
ModbusErrorCode_Success = 0x00,
ModbusErrorCode_IllegalFunction = 0x01,
ModbusErrorCode_IllegalAddr = 0x02,
ModbusErrorCode_IllegalData = 0x03,
ModbusErrorCode_DeviceBusy = 0x06
}modbus_error_code_e;
typedef struct proto_Modbus_t proto_Modbus_t;
struct proto_Modbus_t
{
u8 id;
u16 (*data_read)(u16); /*Modbus读数据*/
modbus_error_code_e (*data_write)(u16,u16); /*Modbus写数据*/
void (*init)(void); /*初始化函数*/
void (*task)(void); /*任务函数*/
void (*data_analysis)(u8 *,u16,void *); /*数据解析*/
};
u16 float_to_u16(float float_data,u8 h_l);
u16 u32_to_u16(u32 u32_Data,u8 h_l);
u32 u8_to_u32(u8 *p_u8_Data,u8 endian);
u16 u8_to_u16(u8 *p_u8_Data,u8 endian);
void u32_to_u8(u32 u32_Data,u8 *p_data,u8 endian);
void u16_to_u8(u16 u16_Data,u8 *p_data,u8 endian);
u32 u32_endian_conv(u32 data);
u16 u16_endian_conv(u16 data);
u16 modbus_lib_crc16(u8 *p_data, u16 len);
void modbus_lib_data_read(u8 Id,u16 Addr,u16 Num,void (*UsartSendBuffer)(u8 *,u16 ));
void modbus_lib_multiple_data_write(u8 ID,u16 Addr,u16 Num,u16 *Data,void (*UsartSendBuffer)(u8 *,u16 ));
void modbus_lib_only_data_write(u8 ID,u16 Addr,u16 Value,void (*UsartSendBuffer)(u8 *,u16 ));
u8 modbus_lib_analysis(modbus_analysis_data_t *p_modbus, u8 *p_data, u16 len);
#endif
@@ -0,0 +1,286 @@
#include "proto_modbus_master_leakage.h"
#include "string.h"
#include "stdio.h"
#include "app.h"
#include "app_timer.h"
#include "bsp_Uart.h"
#include "bsp_Flash.h"
#include "app_leakage.h"
#include "proto_print.h"
#include "proto_modbus_lib.h"
#define PROTO_LEAKAGE_READ_DATA_NUM (14) /*读取一个设备寄存器数量*/
#define PROTO_LEAKAGE_GET_CURR_DATA_START_ADDR (0x0000)
static void proto_leakage_init(proto_leakage_t *p_leakage);
static void proto_leakage_tx_task(proto_leakage_t *p_leakage);
static void proto_leakage_rx_task(u8 *p_data,u16 len,void *other_data);
static void proto_leakage_com1_uart_send(u8 *p_data,u16 len);
static void proto_leakage_com2_uart_send(u8 *p_data,u16 len);
static void proto_leakage_com3_uart_send(u8 *p_data,u16 len);
static void proto_leakage_com4_uart_send(u8 *p_data,u16 len);
proto_leakage_t modbus_leakage[APP_COM_NUM] =
{
/*COM1*/
{
.init = proto_leakage_init,
.tx_task = proto_leakage_tx_task,
.uart_send = proto_leakage_com1_uart_send,
},
/*COM2*/
{
.init = proto_leakage_init,
.tx_task = proto_leakage_tx_task,
.uart_send = proto_leakage_com2_uart_send,
},
/*COM3*/
{
.init = proto_leakage_init,
.tx_task = proto_leakage_tx_task,
.uart_send = proto_leakage_com3_uart_send,
},
/*COM4*/
{
.init = proto_leakage_init,
.tx_task = proto_leakage_tx_task,
.uart_send = proto_leakage_com4_uart_send,
}
};
static void proto_leakage_init(proto_leakage_t *p_leakage)
{
/*绑定串口解析函数*/
if(p_leakage == &modbus_leakage[APP_COM1])
{
com_to_uart[APP_COM1]->rx_data_analysis = proto_leakage_rx_task;
}
else if(p_leakage == &modbus_leakage[APP_COM2])
{
com_to_uart[APP_COM2]->rx_data_analysis = proto_leakage_rx_task;
}
else if(p_leakage == &modbus_leakage[APP_COM3])
{
com_to_uart[APP_COM3]->rx_data_analysis = proto_leakage_rx_task;
}
else if(p_leakage == &modbus_leakage[APP_COM4])
{
com_to_uart[APP_COM3]->rx_data_analysis = proto_leakage_rx_task;
}
/*绑定modbus_id和对应的索引在app_com中完成*/
}
static void proto_leakage_com1_uart_send(u8 *p_data,u16 len)
{
com_to_uart[APP_COM1]->send(com_to_uart[APP_COM1],p_data,len);
}
static void proto_leakage_com2_uart_send(u8 *p_data,u16 len)
{
com_to_uart[APP_COM2]->send(com_to_uart[APP_COM2],p_data,len);
}
static void proto_leakage_com3_uart_send(u8 *p_data,u16 len)
{
com_to_uart[APP_COM3]->send(com_to_uart[APP_COM3],p_data,len);
}
static void proto_leakage_com4_uart_send(u8 *p_data,u16 len)
{
com_to_uart[APP_COM4]->send(com_to_uart[APP_COM4],p_data,len);
}
/*切换读取的漏液子控*/
static void proto_leakage_switch(proto_leakage_t *p_leakage)
{
p_leakage->sensor_index++;
if(p_leakage->sensor_index >= p_leakage->sensor_num)
{
p_leakage->sensor_index = 0;
}
}
static void proto_leakage_tx_curr_data_get(proto_leakage_t *p_leakage)
{
u16 addr = PROTO_LEAKAGE_GET_CURR_DATA_START_ADDR;
u8 len = 14;
u8 id = p_leakage->sensor[p_leakage->sensor_index].comm.id;
modbus_lib_data_read(id,addr,len,p_leakage->uart_send);
}
static void proto_leakage_tx_task(proto_leakage_t *p_leakage)
{
proto_sensor_class_t *p_sensor;
p_sensor = &p_leakage->sensor[p_leakage->sensor_index];
if(0 == (p_sensor->comm.sensor_state_code & (0x00000001 << PROTO_LEAKAGE_STATE_CODE_TIME_OUT)))
{
if((++p_sensor->comm.tx_time_out_count) > 20)/*500ms轮询 10秒通讯超时*/
{
p_sensor->comm.sensor_state_code |= (0x00000001 << PROTO_LEAKAGE_STATE_CODE_TIME_OUT);
/*清除数据*/
//memset(&gas_data[p_sensor->sensor_index],0,sizeof(gas_data_t));
}
}
switch(p_sensor->comm.state)
{
case PROTO_LEAKAGE_COMM_STATE_CURR_DATA_GET:
{
proto_leakage_tx_curr_data_get(p_leakage);
}break;
default:
{
}break;
}
p_sensor->comm.state_send_time++;
if(p_sensor->comm.state_send_time >= 3) /*进入异常*/
{
p_sensor->comm.sensor_state_code |= (0x00000001 << p_sensor->comm.sensor_state_code);/*记录异常状态*/
p_sensor->comm.state_send_time = 0;
p_sensor->comm.sensor_state_code = PROTO_LEAKAGE_COMM_STATE_DEFAULT;
proto_leakage_switch(p_leakage); /*切换设备*/
}
}
static void proto_leakage_rx_task(u8 *p_data,u16 len,void *other_data)
{
u8 send_flag = 0;
u8 modbus_id,cmd;
u16 check_crc16,modbus_crc16;
u16 *p_u16_temp;
u16 i,ch;
u8 *p_rx_valid,temp_value;
proto_sensor_class_t *p_sensor;
proto_leakage_t *p_leakage = NULL;
/***********************查找漏液对象**************************/
if(other_data == NULL)
{
return;
}
/*查找漏液modbus对象*/
for(i=0;i<4;i++)
{
if( (bsp_uart_t *)other_data == com_to_uart[i] )
{
p_leakage = &modbus_leakage[i];
}
}
if(p_leakage == NULL)
{
return;
}
p_sensor = &p_leakage->sensor[p_leakage->sensor_index];
/***********************modbus解析**************************/
if(p_sensor->comm.id != p_data[0])
{
p_data = &p_data[1];
len -= 1;
}
modbus_id = *p_data;
cmd = *(p_data+1);
check_crc16 = p_data[len-2] << 8 | p_data[len-1];
if(modbus_id != p_sensor->comm.id) return ;
if(cmd != 0x03 && cmd != 0x06 && cmd != 0x10 && cmd != 0x41) return ;
modbus_crc16 = modbus_lib_crc16(p_data,len-2);
modbus_crc16 = (modbus_crc16 >> 8) | (modbus_crc16 << 8);
if(check_crc16 != modbus_crc16) return ;
if(cmd == 0x41)
{
p_rx_valid = &p_data[6];
}
p_rx_valid = &p_data[3];
p_sensor->comm.tx_time_out_count = 0;
p_sensor->comm.sensor_state_code &= (~(0x00000001 << PROTO_LEAKAGE_STATE_CODE_TIME_OUT));
switch(p_sensor->comm.state)
{
case PROTO_LEAKAGE_COMM_STATE_INIT:
{
}break;
case PROTO_LEAKAGE_COMM_STATE_CURR_DATA_GET:
{
/*计算当前设备索引*/
u8 sensor_index = p_leakage->sensor_index;
u16 ch_addr_offset[4] = {0,4,8,11}; /*漏液待数据地址偏移*/
u16 temp;
if(sensor_index >= APP_LEAKAGE_SUB_DEVICE_NUM)
{
break;
}
/*通道数据重置*/
for(ch = 0;ch < APP_LEAKAGE_SUB_DEVICE_CH_NUM;ch++)
{
leakage.sub_device_data[sensor_index].ch_data[ch].state = 0;
leakage.sub_device_data[sensor_index].ch_data[ch].state = 0;
}
/* 心跳包:0x0003*/
temp_value = (p_rx_valid[6] << 8) | p_rx_valid[7];
leakage.sub_device_data[sensor_index].heartbeat = temp_value & 0xFF;
/*测试模式:0x0007*/
temp_value = (p_rx_valid[14] << 8) | p_rx_valid[15];
leakage.sub_device_data[sensor_index].test_mode = temp_value & 0xFF;
/*漏液数据*/
for(i=0;i<4;i++)
{
ch = i;
temp = ch_addr_offset[i];
temp_value = (p_rx_valid[temp + 0] << 8) | p_rx_valid[temp + 1];
if(temp_value == 1)
{
leakage.sub_device_data[sensor_index].ch_data[ch].state |=
APP_LEAKAGE_SUB_DEVICE_STATE_LEAKAGE;
}
temp_value = (p_rx_valid[temp + 2] << 8) | p_rx_valid[temp + 3];
if(temp_value == 1)
{
leakage.sub_device_data[sensor_index].ch_data[ch].state |=
APP_LEAKAGE_SUB_DEVICE_STATE_OPEN;
}
temp_value = (p_rx_valid[temp + 4] << 8) | p_rx_valid[temp + 5];
leakage.sub_device_data[sensor_index].ch_data[ch].distance = temp_value *0.01;
}
}break;
}
if(send_flag)
{
return;
}
else
{
p_sensor->comm.state = PROTO_LEAKAGE_COMM_STATE_DEFAULT;
p_sensor->comm.sensor_state_code &= (~(0x00000001 << p_sensor->comm.state));/*消除异常状态*/
p_sensor->comm.state_send_time = 0;
proto_leakage_switch(p_leakage);
return;
}
}
@@ -0,0 +1,47 @@
#ifndef _PROTO_MODBUS_MASTER_LEAKAGE_H_
#define _PROTO_MODBUS_MASTER_LEAKAGE_H_
#include "main.h"
#include "app_com.h"
#define COMM_SENSOR_NUM_MAX (32) /*最大的通讯数量*/
/*通讯状态*/
#define PROTO_LEAKAGE_COMM_STATE_INIT (0U) /*初始化 */
#define PROTO_LEAKAGE_COMM_STATE_CURR_DATA_GET (1U) /*获取实时数据*/
#define PROTO_LEAKAGE_COMM_STATE_DEFAULT PROTO_LEAKAGE_COMM_STATE_CURR_DATA_GET
#define PROTO_LEAKAGE_STATE_CODE_TIME_OUT (30U) /*通讯超时*/
typedef struct
{
struct /*通讯相关参数*/
{
u8 id; /*modbus通讯id*/
u8 state; /*传感器当前的通讯状态*/
u8 leakage_data_index; /*漏液子控索引*/
u16 state_send_time; /*当前通讯状态发送次数*/
u16 tx_time_out_count; /*协议指令发送次数*/
u32 sensor_state_code; /*传感器状态码,为对应位为1代表异常*/
}comm;
}proto_sensor_class_t;
typedef struct proto_leakage_t proto_leakage_t;
struct proto_leakage_t
{
u16 sensor_index; /*当前与哪个传感器通讯*/
u16 sensor_num; /*总共通讯的传感器数量*/
proto_sensor_class_t sensor[APP_LEAKAGE_SUB_DEVICE_NUM]; /*传感器状态*/
void (*init)(proto_leakage_t *);
void (*tx_task)(proto_leakage_t *);
void (*uart_send)(u8 *,u16);
};
extern proto_leakage_t modbus_leakage[APP_COM_NUM];
#endif
@@ -0,0 +1,326 @@
/*对外通讯 modbus从机*/
#include "proto_modbus_slave_ex.h"
#include "string.h"
#include "stdio.h"
#include "app.h"
#include "app_timer.h"
#include "bsp_relay.h"
#include "bsp_Uart.h"
#include "bsp_Flash.h"
#include "proto_print.h"
#include "proto_modbus_master_leakage.h"
static modbus_analysis_data_t modbus_analysis_data;//指令解析结构体
static modbus_communication_send_buf_t send_struct;//发送结构体
static void proto_modbus_communication_data_analysis(u8 *pData, u16 len, void *data);
static void proto_modbus_communication_data_send(u8 *pData, u16 len);
static void proto_modbus_init(void);
static void proto_modbus_task(void);
static modbus_error_code_e proto_modbus_data_write(u16 Addr, u16 Value);
static u16 proto_modbus_data_read(u16 Addr);
proto_Modbus_t modbus_slave_ex=
{
.id = 0x01,
.data_read = proto_modbus_data_read,
.data_write = proto_modbus_data_write,
.data_analysis = proto_modbus_communication_data_analysis,
.init = proto_modbus_init,
.task = proto_modbus_task,
};
static proto_Modbus_t *p_modbus = &modbus_slave_ex;
static bsp_uart_t * p_rx_uart;
static void proto_modbus_communication_data_send(u8 *p_data, u16 len)
{
if(p_rx_uart != NULL)
{
p_rx_uart->send(p_rx_uart,p_data,len);
}
}
static void proto_modbus_init(void)
{
p_modbus->id = Usr_Flash.FlashData.modbus_id;
com_uart1.rx_data_analysis = proto_modbus_communication_data_analysis;
com_uart4.rx_data_analysis = proto_modbus_communication_data_analysis;
}
static void proto_modbus_task(void)
{
}
static void proto_modbus_communication_data_analysis(u8 *pData, u16 len,void *other_data)
{
modbus_error_code_e error_code;
u16 inx;
u16 TempAddr, TempData, crc_16;
if (0 == modbus_lib_analysis(&modbus_analysis_data, pData, len))//检查数据长度 校验是否正确
return;
if (p_modbus->id != modbus_analysis_data.id && modbus_analysis_data.id != 0xe8)//判断ID是否正确
return;
error_code = ModbusErrorCode_Success;
/* //检查地址是否超出范围
if ((modbus_analysis_data.start_addr >= MODBUS_REG_LEN) || (modbus_analysis_data.reg_number >= MODBUS_REG_LEN) ||
(modbus_analysis_data.start_addr + modbus_analysis_data.reg_number >= MODBUS_REG_LEN))
{
ErrorCode = ModbusErrorCode_IllegalAddr;
goto Error;
}
*/
p_rx_uart = (bsp_uart_t*)other_data;
switch (modbus_analysis_data.func)
{
case 0x03:
case 0x04:
{
TempAddr = modbus_analysis_data.start_addr;
send_struct.send_buffer[0] = modbus_analysis_data.id;
send_struct.send_buffer[1] = modbus_analysis_data.func;
send_struct.send_buffer[2] = 2 * modbus_analysis_data.reg_number;
for (inx = 0; inx < modbus_analysis_data.reg_number; inx++)
{
TempData = proto_modbus_data_read(TempAddr);
send_struct.send_buffer[3 + 2 * inx] = (TempData >> 8) & 0xff;
send_struct.send_buffer[4 + 2 * inx] = TempData & 0xff;
TempAddr++;
}
crc_16 = modbus_lib_crc16(send_struct.send_buffer, 3 + send_struct.send_buffer[2]);
send_struct.send_buffer[3 + send_struct.send_buffer[2]] = crc_16 & 0xff;
send_struct.send_buffer[4 + send_struct.send_buffer[2]] = (crc_16 >> 8) & 0xff;
send_struct.len = 5 + send_struct.send_buffer[2];
}goto Success;
/*特殊协议*/
case 0x41:
{
TempAddr = modbus_analysis_data.start_addr;
send_struct.send_buffer[0] = modbus_analysis_data.id;
send_struct.send_buffer[1] = modbus_analysis_data.func;
send_struct.send_buffer[2] = modbus_analysis_data.start_addr >> 8;
send_struct.send_buffer[3] = modbus_analysis_data.start_addr & 0xff;
send_struct.send_buffer[4] = (2 * modbus_analysis_data.reg_number) >> 8;
send_struct.send_buffer[5] = (2 * modbus_analysis_data.reg_number) & 0xff;
for (inx = 0; inx < modbus_analysis_data.reg_number; inx++)
{
TempData = proto_modbus_data_read(TempAddr);
send_struct.send_buffer[6 + 2 * inx] = (TempData >> 8) & 0xff;
send_struct.send_buffer[7 + 2 * inx] = TempData & 0xff;
TempAddr++;
}
crc_16 = modbus_lib_crc16(send_struct.send_buffer, 6 + 2 * modbus_analysis_data.reg_number);
send_struct.send_buffer[6 + 2 * modbus_analysis_data.reg_number] = crc_16 & 0xff;
send_struct.send_buffer[7 + 2 * modbus_analysis_data.reg_number] = (crc_16 >> 8) & 0xff;
send_struct.len = 8 + 2 * modbus_analysis_data.reg_number;
}goto Success;
case 0x06:
{
TempAddr = modbus_analysis_data.start_addr;
TempData = (modbus_analysis_data.write_data_addr[0] << 8) | modbus_analysis_data.write_data_addr[1];
error_code = proto_modbus_data_write(TempAddr, TempData);
if (error_code)
{
goto Error;
}
send_struct.len = 8;
send_struct.send_buffer[0] = modbus_analysis_data.id;
send_struct.send_buffer[1] = modbus_analysis_data.func;
send_struct.send_buffer[2] = modbus_analysis_data.start_addr >> 8;
send_struct.send_buffer[3] = modbus_analysis_data.start_addr & 0xff;
send_struct.send_buffer[4] = modbus_analysis_data.write_data_addr[0];
send_struct.send_buffer[5] = modbus_analysis_data.write_data_addr[1];
crc_16 = modbus_lib_crc16(send_struct.send_buffer, 6);
send_struct.send_buffer[6] = crc_16 & 0xff;
send_struct.send_buffer[7] = (crc_16 >> 8) & 0xff;
}break;
case 0x10:
{
TempAddr = modbus_analysis_data.start_addr;
for (inx = 0; inx < modbus_analysis_data.reg_number; inx++)
{
TempData = modbus_analysis_data.write_data_addr[2 * inx];
TempData = (TempData << 8) | modbus_analysis_data.write_data_addr[2 * inx + 1];
error_code = proto_modbus_data_write(TempAddr, TempData);
TempAddr++;
if (error_code)
{
goto Error;
}
}
send_struct.len = 8;
send_struct.send_buffer[0] = modbus_analysis_data.id;
send_struct.send_buffer[1] = modbus_analysis_data.func;
send_struct.send_buffer[2] = modbus_analysis_data.start_addr >> 8;
send_struct.send_buffer[3] = modbus_analysis_data.start_addr & 0xff;
send_struct.send_buffer[4] = modbus_analysis_data.reg_number >> 8;
send_struct.send_buffer[5] = modbus_analysis_data.reg_number & 0xff;
crc_16 = modbus_lib_crc16(send_struct.send_buffer, 6);
send_struct.send_buffer[6] = crc_16 & 0xff;
send_struct.send_buffer[7] = (crc_16 >> 8) & 0xff;
}
break;
default:
{
error_code = ModbusErrorCode_IllegalFunction;
}
goto Error;
}
Success:
proto_modbus_communication_data_send(send_struct.send_buffer, send_struct.len);
return;
Error:
send_struct.len = 5;
send_struct.send_buffer[0] = modbus_analysis_data.id;
send_struct.send_buffer[1] = modbus_analysis_data.func | 0x80;
send_struct.send_buffer[2] = error_code;
crc_16 = modbus_lib_crc16(send_struct.send_buffer, 3);
send_struct.send_buffer[3] = crc_16 & 0xff;
send_struct.send_buffer[4] = (crc_16 >> 8) & 0xff;
proto_modbus_communication_data_send(send_struct.send_buffer, send_struct.len);
}
/******************************************
* 函数: proto_modbus_data_write
* 功能: Modbus写寄存器
* 参数: Addr: 地址
Value:数据
* 返回: 无
* 描述: 无
******************************************/
static modbus_error_code_e proto_modbus_data_write(u16 addr, u16 data)
{
modbus_error_code_e error_code;
u8 temp_point,cali_point;
error_code = ModbusErrorCode_Success;
switch(addr)
{
case 1 ... 4:
{
relay.set(addr-1,data);
}break;
/*sn*/
case 20000 ... 20004:
{
Usr_Flash.FlashData.sn[addr - 20000] = data;
Usr_Flash.Write();
}break;
/*modbus_id*/
case 20005:
{
Usr_Flash.FlashData.modbus_id = data;
modbus_slave_ex.id = Usr_Flash.FlashData.modbus_id;
Usr_Flash.Write();
}break;
/*modbus_read_reg_num*/
case 20006:
{
if(data > 1000)
{
error_code = ModbusErrorCode_IllegalData;
}
else
{
Usr_Flash.FlashData.modbus_read_reg_num = data;
Usr_Flash.Write();
}
}break;
case 20007:
{
if(data > 16)
{
error_code = ModbusErrorCode_IllegalData;
}
else
{
Usr_Flash.FlashData.modbus_read_sensor_num = data;
Usr_Flash.Write();
}
}break;
/*FC打印相关数据*/
case 252:
{
print.set(data);
}break;
}
return error_code;
}
/******************************************
* 函数: proto_modbus_data_read
* 功能: Modbus读寄存器数据
* 参数: Addr: 地址
* 返回: 地址对应的数据
* 描述: 无
******************************************/
static u16 proto_modbus_data_read(u16 addr)
{
u16 data = 0;
u16 *p_data;
u16 num,offset;
switch(addr)
{
case 1 ... 4:
{
data = relay.state[addr - 1];
}break;
// /*实时数据*/
// case 0 ... 639:
// {
// u16 size;
// size = sizeof(gas_data_t);
// /* TDLAS默认读取*/
// if( size== (2 * Usr_Flash.FlashData.modbus_read_reg_num))
// {
// p_data = (u16 *)&gas_data;
// data = p_data[addr];
// }
// else if((2 * Usr_Flash.FlashData.modbus_read_reg_num )< sizeof(gas_data_t))/*其他传感器*/
// {
// num = addr / Usr_Flash.FlashData.modbus_read_reg_num;
// offset = addr % Usr_Flash.FlashData.modbus_read_reg_num;
// p_data = (u16 *)&gas_data[num];
// data = p_data[offset];
// }
//
// }break;
//
// /*sn*/
// case 20000 ... 20004:
// {
// data = Usr_Flash.FlashData.sn[addr - 20000];
// }break;
// /*modbus_id*/
// case 20005:
// {
// data = Usr_Flash.FlashData.modbus_id;
// }break;
// /*modbus_read_reg_num*/
// case 20006:
// {
// data = Usr_Flash.FlashData.modbus_read_reg_num;
// }break;
// case 20007:
// {
// data = Usr_Flash.FlashData.modbus_read_sensor_num;
// }break;
default:data = 0;
}
return data;
}
@@ -0,0 +1,9 @@
#ifndef _PROTO_MODBUS_SLAVE_EX_H_
#define _PROTO_MODBUS_SLAVE_EX_H_
#include "main.h"
#include "gas_data.h"
#include "proto_modbus_lib.h"
extern proto_Modbus_t modbus_slave_ex;
#endif
+64
View File
@@ -0,0 +1,64 @@
#include "proto_print.h"
#include "stdio.h"
#include "bsp_Uart.h"
u16 proto_print_data_type;
void proto_print_datatype_set(u8 type);
static void proto_print_task(void);
proto_print_t print =
{
.task = proto_print_task,
.set = proto_print_datatype_set,
};
proto_print_t *p_print = &print;
static void proto_print_datatype_set(u8 type)
{
if(type > PROTO_PRINT_MAX)
{
}
else
{
if(proto_print_data_type == type)
{
proto_print_data_type = PROTO_PRINT_NULL;
}
else
{
proto_print_data_type = type;
}
}
}
static void proto_print_task(void)
{
switch(proto_print_data_type)
{
case PROTO_PRINT_NULL:
{
}break;
case PROTO_PRINT_CURDATA:
{
}break;
case PROTO_PRINT_WAVE:
{
}break;
case PROTO_PRINT_CALIB:
{
}break;
default:
{
}break;
}
}
+21
View File
@@ -0,0 +1,21 @@
#ifndef _PROTO_PRINT_H_
#define _PROTO_PRINT_H_
#include "main.h"
#define PROTO_PRINT_MAX 3
#define PROTO_PRINT_NULL 0
#define PROTO_PRINT_CURDATA 1
#define PROTO_PRINT_WAVE 2
#define PROTO_PRINT_CALIB 3
typedef struct
{
void (*task)(void);
void (*set)(u8);
}proto_print_t;
extern proto_print_t print;
#endif