初版程序
This commit is contained in:
@@ -0,0 +1,372 @@
|
||||
#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 u32 g_time_sec_base = 0; // 绝对秒数基准(从 2000-01-01 起)
|
||||
static u32 g_time_tick_base = 0; // 对应的 HAL Tick 值(毫秒)
|
||||
|
||||
static void bsp_DS1302Init(void);
|
||||
static void bsp_DS1302_Task(void);
|
||||
static u8 bsp_DS1302_Set(bsp_DS1302_Time_t *pTime);
|
||||
static void bsp_DS1302DataInput(void);
|
||||
static void bsp_DS1302DataOutput(void);
|
||||
static void bsp_DS1302_write_byte(u8 Addr, u8 Data);
|
||||
static u8 bsp_DS1302_read_byte(u8 Addr);
|
||||
static u8 HexToBCD(u8 code);
|
||||
static u8 is_leap_year(u16 year);
|
||||
static void bsp_DS1302_UpdateBase(void);
|
||||
static void bsp_DS1302_GetTimeWithMs(char *buf, u16 len);
|
||||
static u32 bsp_DS1302_GetCurrentSeconds(void);
|
||||
static u8 bsp_DS1302_SetTimeWithMs(u16 year, u8 month, u8 day,
|
||||
u8 hour, u8 minute, u8 second, u32 ms);
|
||||
static u32 datetime_to_seconds(u16 year, u8 month, u8 day,
|
||||
u8 hour, u8 minute, u8 second);
|
||||
static void seconds_to_datetime(u32 seconds, u16 *year, u8 *month, u8 *day,
|
||||
u8 *hour, u8 *minute, u8 *second);
|
||||
|
||||
bsp_DS1302_t DS1302 =
|
||||
{
|
||||
.Init = bsp_DS1302Init,
|
||||
.Task = bsp_DS1302_Task,
|
||||
.Set = bsp_DS1302_Set,
|
||||
.UpdateBase = bsp_DS1302_UpdateBase,
|
||||
.GetTimeWithMs = bsp_DS1302_GetTimeWithMs,
|
||||
.GetCurrentSeconds = bsp_DS1302_GetCurrentSeconds,
|
||||
.SetTimeWithMs = bsp_DS1302_SetTimeWithMs,
|
||||
};
|
||||
|
||||
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 is_leap_year(u16 year)
|
||||
{
|
||||
return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
|
||||
}
|
||||
|
||||
static u32 datetime_to_seconds(u16 year, u8 month, u8 day,
|
||||
u8 hour, u8 minute, u8 second)
|
||||
{
|
||||
const u8 month_days[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
|
||||
u32 days = 0;
|
||||
for (u16 y = 2000; y < year; y++) {
|
||||
days += 365 + is_leap_year(y);
|
||||
}
|
||||
for (u8 m = 1; m < month; m++) {
|
||||
days += month_days[m-1];
|
||||
if (m == 2 && is_leap_year(year)) days++;
|
||||
}
|
||||
days += (day - 1);
|
||||
return days * 86400UL + hour * 3600UL + minute * 60UL + second;
|
||||
}
|
||||
|
||||
static void seconds_to_datetime(u32 seconds, u16 *year, u8 *month, u8 *day,
|
||||
u8 *hour, u8 *minute, u8 *second)
|
||||
{
|
||||
u32 days = seconds / 86400;
|
||||
u32 secs_rem = seconds % 86400;
|
||||
u16 y = 2000;
|
||||
while (1) {
|
||||
u16 days_in_year = 365 + is_leap_year(y);
|
||||
if (days < days_in_year) break;
|
||||
days -= days_in_year;
|
||||
y++;
|
||||
}
|
||||
*year = y;
|
||||
u8 month_days[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
|
||||
if (is_leap_year(y)) month_days[1] = 29;
|
||||
u8 m;
|
||||
for (m = 1; m <= 12; m++) {
|
||||
if (days < month_days[m-1]) break;
|
||||
days -= month_days[m-1];
|
||||
}
|
||||
*month = m;
|
||||
*day = days + 1;
|
||||
*hour = secs_rem / 3600;
|
||||
*minute = (secs_rem % 3600) / 60;
|
||||
*second = secs_rem % 60;
|
||||
}
|
||||
|
||||
// ---------- 新增毫秒级扩展功能实现 ----------
|
||||
static void bsp_DS1302_UpdateBase(void)
|
||||
{
|
||||
u16 year = 2000 + DS1302.Time.Year;
|
||||
g_time_sec_base = datetime_to_seconds(year, DS1302.Time.Month, DS1302.Time.Day,
|
||||
DS1302.Time.Hour, DS1302.Time.Minute, DS1302.Time.Second);
|
||||
g_time_tick_base = HAL_GetTick();
|
||||
}
|
||||
|
||||
static void bsp_DS1302_GetTimeWithMs(char *buf, u16 len)
|
||||
{
|
||||
if (!buf || len < 17) return;
|
||||
u32 tick_diff = HAL_GetTick() - g_time_tick_base; // 自动处理回绕
|
||||
u32 total_sec = g_time_sec_base + tick_diff / 1000;
|
||||
u32 ms = tick_diff % 1000;
|
||||
u16 year; u8 month, day, hour, minute, second;
|
||||
seconds_to_datetime(total_sec, &year, &month, &day, &hour, &minute, &second);
|
||||
u8 ms_two_digits = ms / 10;
|
||||
snprintf(buf, len, "%04d%02d%02d%02d%02d%02d%02d",
|
||||
year, month, day, hour, minute, second, ms_two_digits);
|
||||
}
|
||||
|
||||
static u32 bsp_DS1302_GetCurrentSeconds(void)
|
||||
{
|
||||
u32 tick_diff = HAL_GetTick() - g_time_tick_base;
|
||||
return g_time_sec_base + tick_diff / 1000;
|
||||
}
|
||||
|
||||
static u8 bsp_DS1302_SetTimeWithMs(u16 year, u8 month, u8 day,
|
||||
u8 hour, u8 minute, u8 second, u32 ms)
|
||||
{
|
||||
if (year < 2000 || year > 2099 || month < 1 || month > 12 ||
|
||||
day < 1 || day > 31 || hour > 23 || minute > 59 || second > 59 || ms > 99) {
|
||||
return 0;
|
||||
}
|
||||
bsp_DS1302_Time_t time;
|
||||
time.Year = year - 2000;
|
||||
time.Month = month;
|
||||
time.Day = day;
|
||||
time.Hour = hour;
|
||||
time.Minute = minute;
|
||||
time.Second = second;
|
||||
if (bsp_DS1302_Set(&time) != 1) {
|
||||
return 0;
|
||||
}
|
||||
// 校准基准
|
||||
u32 actual_ms = ms * 10;
|
||||
g_time_sec_base = datetime_to_seconds(year, month, day, hour, minute, second);
|
||||
g_time_tick_base = HAL_GetTick() - actual_ms;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static u8 bsp_DS1302_Set(bsp_DS1302_Time_t *pTime)
|
||||
{
|
||||
if ((pTime->Year > 99) || (pTime->Month > 12) || (pTime->Day > 31) ||
|
||||
(pTime->Hour > 23) || (pTime->Minute > 59) || (pTime->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 = 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
#ifndef __BSP_DS1302_H__
|
||||
#define __BSP_DS1302_H__
|
||||
|
||||
#include "main.h"
|
||||
#include "string.h"
|
||||
#include "stdio.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);
|
||||
void(*UpdateBase)(void);
|
||||
void(*GetTimeWithMs)(char *buf, u16 len);
|
||||
u32(*GetCurrentSeconds)(void);
|
||||
u8(*SetTimeWithMs)(u16 year, u8 month, u8 day,
|
||||
u8 hour, u8 minute, u8 second, u32 ms);
|
||||
}bsp_DS1302_t;
|
||||
|
||||
extern bsp_DS1302_t DS1302;//系统时间
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1 @@
|
||||
#include "bsp_Delay.h"
|
||||
@@ -0,0 +1,6 @@
|
||||
#ifndef _BSP_DELAY_H_
|
||||
#define _BSP_DELAY_H_
|
||||
|
||||
#include "main.h"
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,374 @@
|
||||
#include "bsp_Flash.h"
|
||||
#include "string.h"
|
||||
#include "bsp_Wdg.h"
|
||||
#include "bsp_W5500.h"
|
||||
#include "bsp_W5500_1.h"
|
||||
#include "proto_HSMS.h"
|
||||
/* FLASH Memory Definitions */
|
||||
#define BSP_FLASH_SIZE (0x10000UL)
|
||||
#define BSP_FLASH_PAGE_SIZE (FLASH_PAGE_SIZE)
|
||||
#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)
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
// 擦除指定页
|
||||
static HAL_StatusTypeDef bsp_FLASH_ErasePage(uint32_t PageAddress)
|
||||
{
|
||||
FLASH_EraseInitTypeDef EraseInitStruct;
|
||||
uint32_t PageError = 0;
|
||||
|
||||
EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;
|
||||
EraseInitStruct.PageAddress = PageAddress;
|
||||
EraseInitStruct.NbPages = 1;
|
||||
|
||||
return HAL_FLASHEx_Erase(&EraseInitStruct, &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)
|
||||
{
|
||||
u16 port = 5002;
|
||||
Usr_Flash.FlashData.IP_Addr[0] = 10;
|
||||
Usr_Flash.FlashData.IP_Addr[1] = 21;
|
||||
Usr_Flash.FlashData.IP_Addr[2] = 54;
|
||||
Usr_Flash.FlashData.IP_Addr[3] = 2;
|
||||
|
||||
Usr_Flash.FlashData.Port[0] = port >> 8;
|
||||
Usr_Flash.FlashData.Port[1] = port & 0x00ff;
|
||||
|
||||
Usr_Flash.FlashData.Sub_Mask[0] = 255;
|
||||
Usr_Flash.FlashData.Sub_Mask[1] = 255;
|
||||
Usr_Flash.FlashData.Sub_Mask[2] = 252;
|
||||
Usr_Flash.FlashData.Sub_Mask[3] = 0;
|
||||
|
||||
Usr_Flash.FlashData.Gateway_IP[0] = 10;
|
||||
Usr_Flash.FlashData.Gateway_IP[1] = 21;
|
||||
Usr_Flash.FlashData.Gateway_IP[2] = 52;
|
||||
Usr_Flash.FlashData.Gateway_IP[3] = 1;
|
||||
|
||||
Usr_Flash.FlashData.Devic_Id = 0;
|
||||
|
||||
/*客户端主机网络配置*/
|
||||
u16 port_1 = 5000;
|
||||
u16 port_2 = 502;
|
||||
Usr_Flash.FlashData.IP_Addr_1[0] = 192;
|
||||
Usr_Flash.FlashData.IP_Addr_1[1] = 168;
|
||||
Usr_Flash.FlashData.IP_Addr_1[2] = 100;
|
||||
Usr_Flash.FlashData.IP_Addr_1[3] = 103;
|
||||
|
||||
Usr_Flash.FlashData.Port_1[0] = port_1 >> 8;
|
||||
Usr_Flash.FlashData.Port_1[1] = port_1 & 0x00ff;
|
||||
|
||||
Usr_Flash.FlashData.Sub_Mask_1[0] = 255;
|
||||
Usr_Flash.FlashData.Sub_Mask_1[1] = 255;
|
||||
Usr_Flash.FlashData.Sub_Mask_1[2] = 255;
|
||||
Usr_Flash.FlashData.Sub_Mask_1[3] = 0;
|
||||
|
||||
Usr_Flash.FlashData.Gateway_IP_1[0] = 192;
|
||||
Usr_Flash.FlashData.Gateway_IP_1[1] = 168;
|
||||
Usr_Flash.FlashData.Gateway_IP_1[2] = 100;
|
||||
Usr_Flash.FlashData.Gateway_IP_1[3] = 1;
|
||||
|
||||
/*客户端目标IP*/
|
||||
Usr_Flash.FlashData.IP_Addr_2[0] = 192;
|
||||
Usr_Flash.FlashData.IP_Addr_2[1] = 168;
|
||||
Usr_Flash.FlashData.IP_Addr_2[2] = 100;
|
||||
Usr_Flash.FlashData.IP_Addr_2[3] = 61;
|
||||
|
||||
Usr_Flash.FlashData.Port_2[0] = port_2 >> 8;
|
||||
Usr_Flash.FlashData.Port_2[1] = port_2 & 0x00ff;
|
||||
|
||||
Usr_Flash.FlashData.Devic_Id_1 = 0;
|
||||
|
||||
bsp_FlashDataWrite();
|
||||
}
|
||||
|
||||
static void bsp_flash_device_resset(void)
|
||||
{
|
||||
|
||||
/* ================== 清空所有字符串字段 ================== */
|
||||
memset(Usr_Flash.FlashData.Device_SN, 0, sizeof(Usr_Flash.FlashData.Device_SN));
|
||||
memset(Usr_Flash.FlashData.Device_Model, 0, sizeof(Usr_Flash.FlashData.Device_Model));
|
||||
memset(Usr_Flash.FlashData.Station_Type, 0, sizeof(Usr_Flash.FlashData.Station_Type));
|
||||
memset(Usr_Flash.FlashData.Device_ID, 0, sizeof(Usr_Flash.FlashData.Device_ID));
|
||||
memset(Usr_Flash.FlashData.Version, 0, sizeof(Usr_Flash.FlashData.Version));
|
||||
memset(Usr_Flash.FlashData.Manufacturer, 0, sizeof(Usr_Flash.FlashData.Manufacturer));
|
||||
memset(Usr_Flash.FlashData.Station_Name, 0, sizeof(Usr_Flash.FlashData.Station_Name));
|
||||
memset(Usr_Flash.FlashData.Chamber_Name, 0, sizeof(Usr_Flash.FlashData.Chamber_Name));
|
||||
|
||||
// 1. 机台和位置:OS_S_ABDDE01_A_31P (20字符 → 10个 u16)
|
||||
Usr_Flash.FlashData.Device_Model[0] = ((u16)'S' << 8) | 'O'; // "OS"
|
||||
Usr_Flash.FlashData.Device_Model[1] = ((u16)'S' << 8) | '_'; // "_S"
|
||||
Usr_Flash.FlashData.Device_Model[2] = ((u16)'A' << 8) | '_'; // "_A"
|
||||
Usr_Flash.FlashData.Device_Model[3] = ((u16)'D' << 8) | 'B'; // "BD"
|
||||
Usr_Flash.FlashData.Device_Model[4] = ((u16)'E' << 8) | 'D'; // "DE"
|
||||
Usr_Flash.FlashData.Device_Model[5] = ((u16)'0' << 8) | '1'; // "01"
|
||||
Usr_Flash.FlashData.Device_Model[6] = ((u16)'A' << 8) | '_'; // "_A"
|
||||
Usr_Flash.FlashData.Device_Model[7] = ((u16)'3' << 8) | '_'; // "_3"
|
||||
Usr_Flash.FlashData.Device_Model[8] = ((u16)'P' << 8) | '1'; // "1P"
|
||||
// 第9个元素已经清零 (Device_Model[9] = 0)
|
||||
|
||||
// 2. 设备型号:SJPW1500DB-650S-208 (19字符)
|
||||
Usr_Flash.FlashData.Device_ID[0] = ((u16)'J' << 8) | 'S'; // "SJ"
|
||||
Usr_Flash.FlashData.Device_ID[1] = ((u16)'W' << 8) | 'P'; // "PW"
|
||||
Usr_Flash.FlashData.Device_ID[2] = ((u16)'5' << 8) | '1'; // "15"
|
||||
Usr_Flash.FlashData.Device_ID[3] = ((u16)'0' << 8) | '0'; // "00"
|
||||
Usr_Flash.FlashData.Device_ID[4] = ((u16)'B' << 8) | 'D'; // "DB"
|
||||
Usr_Flash.FlashData.Device_ID[5] = ((u16)'6' << 8) | '-'; // "-6"
|
||||
Usr_Flash.FlashData.Device_ID[6] = ((u16)'0' << 8) | '5'; // "50"
|
||||
Usr_Flash.FlashData.Device_ID[7] = ((u16)'-' << 8) | 'S'; // "S-"
|
||||
Usr_Flash.FlashData.Device_ID[8] = ((u16)'0' << 8) | '2'; // "20"
|
||||
Usr_Flash.FlashData.Device_ID[9] = ((u16)0 << 8) | '8'; // "8" + '\0'
|
||||
|
||||
// 3. 设备类型:SCRUBBER (8字符 → 4个u16)
|
||||
Usr_Flash.FlashData.Station_Type[0] = ((u16)'C' << 8) | 'S'; // "SC"
|
||||
Usr_Flash.FlashData.Station_Type[1] = ((u16)'U' << 8) | 'R'; // "RU"
|
||||
Usr_Flash.FlashData.Station_Type[2] = ((u16)'B' << 8) | 'B'; // "BB"
|
||||
Usr_Flash.FlashData.Station_Type[3] = ((u16)'R' << 8) | 'E'; // "ER"
|
||||
// 其余已清零
|
||||
|
||||
// 4. 机台名称:ABCDE11 (7字符 → 4个u16,最后一对为 '1' + '\0')
|
||||
Usr_Flash.FlashData.Station_Name[0] = ((u16)'B' << 8) | 'A'; // "AB"
|
||||
Usr_Flash.FlashData.Station_Name[1] = ((u16)'D' << 8) | 'C'; // "CD"
|
||||
Usr_Flash.FlashData.Station_Name[2] = ((u16)'1' << 8) | 'E'; // "E1"
|
||||
Usr_Flash.FlashData.Station_Name[3] = ((u16)0 << 8) | '1'; // "1"
|
||||
// 其余已清零
|
||||
|
||||
// 5. 腔体名称:ABCDE11 (与机台名称相同)
|
||||
Usr_Flash.FlashData.Chamber_Name[0] = ((u16)'B' << 8) | 'A'; // "AB"
|
||||
Usr_Flash.FlashData.Chamber_Name[1] = ((u16)'D' << 8) | 'C'; // "CD"
|
||||
Usr_Flash.FlashData.Chamber_Name[2] = ((u16)'1' << 8) | 'E'; // "E1"
|
||||
Usr_Flash.FlashData.Chamber_Name[3] = ((u16)0 << 8) | '1'; // "1"
|
||||
// 其余已清零
|
||||
|
||||
// 6. 厂商名称:SJ (2字符 → 1个u16)
|
||||
Usr_Flash.FlashData.Manufacturer[0] = ((u16)'J' << 8) | 'S'; // "SJ"
|
||||
// 其余已清零
|
||||
|
||||
// 7. 软件版本:V02.04.00.00_00.07_V4.1 (23字符数)
|
||||
Usr_Flash.FlashData.Version[0] = ((u16)'0' << 8) | 'V'; // "V0"
|
||||
Usr_Flash.FlashData.Version[1] = ((u16)'.' << 8) | '2'; // "2."
|
||||
Usr_Flash.FlashData.Version[2] = ((u16)'4' << 8) | '0'; // "04"
|
||||
Usr_Flash.FlashData.Version[3] = ((u16)'0' << 8) | '.'; // ".0"
|
||||
Usr_Flash.FlashData.Version[4] = ((u16)'.' << 8) | '0'; // "0."
|
||||
Usr_Flash.FlashData.Version[5] = ((u16)'0' << 8) | '0'; // "00"
|
||||
Usr_Flash.FlashData.Version[6] = ((u16)'0' << 8) | '_'; // "_0"
|
||||
Usr_Flash.FlashData.Version[7] = ((u16)'.' << 8) | '0'; // "0."
|
||||
Usr_Flash.FlashData.Version[8] = ((u16)'7' << 8) | '0'; // "07"
|
||||
Usr_Flash.FlashData.Version[9] = ((u16)'V' << 8) | '_'; // "_V"
|
||||
Usr_Flash.FlashData.Version[10] = ((u16)'.' << 8) | '4'; // "4."
|
||||
Usr_Flash.FlashData.Version[11] = ((u16)0 << 8) | '1'; // "1"
|
||||
|
||||
/* 其他字段无需改动,写入 Flash */
|
||||
bsp_FlashDataWrite();
|
||||
|
||||
}
|
||||
|
||||
static void bsp_Flash_Init(void)
|
||||
{
|
||||
u8 i;
|
||||
|
||||
bsp_FlashDataRead();
|
||||
if( Usr_Flash.FlashData.IP_Addr[0] == 0xff
|
||||
&& Usr_Flash.FlashData.IP_Addr[1] == 0xff
|
||||
&& Usr_Flash.FlashData.IP_Addr[2] == 0xff
|
||||
&& Usr_Flash.FlashData.IP_Addr[3] == 0xff
|
||||
)
|
||||
{
|
||||
bsp_FlashReset();
|
||||
}
|
||||
|
||||
if( Usr_Flash.FlashData.Device_Model[0] == 0xffff
|
||||
&& Usr_Flash.FlashData.Device_Model[1] == 0xffff
|
||||
&& Usr_Flash.FlashData.Device_Model[2] == 0xffff
|
||||
&& Usr_Flash.FlashData.Device_Model[3] == 0xffff
|
||||
&& Usr_Flash.FlashData.Device_Model[4] == 0xffff
|
||||
&& Usr_Flash.FlashData.Device_Model[5] == 0xffff
|
||||
&& Usr_Flash.FlashData.Device_Model[6] == 0xffff
|
||||
&& Usr_Flash.FlashData.Device_Model[7] == 0xffff
|
||||
&& Usr_Flash.FlashData.Device_Model[8] == 0xffff
|
||||
&& Usr_Flash.FlashData.Device_Model[9] == 0xffff
|
||||
)
|
||||
{
|
||||
bsp_flash_device_resset();
|
||||
}
|
||||
|
||||
memcpy(&Usr_Flash.TempFlashData, &Usr_Flash.FlashData, sizeof(bsp_FlashData_t));
|
||||
W5500.IP_Addr[0] = Usr_Flash.FlashData.IP_Addr[0];
|
||||
W5500.IP_Addr[1] = Usr_Flash.FlashData.IP_Addr[1];
|
||||
W5500.IP_Addr[2] = Usr_Flash.FlashData.IP_Addr[2];
|
||||
W5500.IP_Addr[3] = Usr_Flash.FlashData.IP_Addr[3];
|
||||
|
||||
W5500.Gateway_IP[0] =Usr_Flash.FlashData.Gateway_IP[0];
|
||||
W5500.Gateway_IP[1]=Usr_Flash.FlashData.Gateway_IP[1];
|
||||
W5500.Gateway_IP[2]=Usr_Flash.FlashData.Gateway_IP[2];
|
||||
W5500.Gateway_IP[3]=Usr_Flash.FlashData.Gateway_IP[3];
|
||||
|
||||
W5500.W5500_Class[0].ConfigData.Port[0] = Usr_Flash.FlashData.Port[0];
|
||||
W5500.W5500_Class[0].ConfigData.Port[1] = Usr_Flash.FlashData.Port[1];
|
||||
|
||||
W5500.Sub_Mask[0] = Usr_Flash.FlashData.Sub_Mask[0];
|
||||
W5500.Sub_Mask[1] = Usr_Flash.FlashData.Sub_Mask[1];
|
||||
W5500.Sub_Mask[2] = Usr_Flash.FlashData.Sub_Mask[2];
|
||||
W5500.Sub_Mask[3] = Usr_Flash.FlashData.Sub_Mask[3];
|
||||
|
||||
/*客户端主机网络配置*/
|
||||
W5500_1.IP_Addr[0] = Usr_Flash.FlashData.IP_Addr_1[0];
|
||||
W5500_1.IP_Addr[1] = Usr_Flash.FlashData.IP_Addr_1[1];
|
||||
W5500_1.IP_Addr[2] = Usr_Flash.FlashData.IP_Addr_1[2];
|
||||
W5500_1.IP_Addr[3] = Usr_Flash.FlashData.IP_Addr_1[3];
|
||||
|
||||
W5500_1.Gateway_IP[0] =Usr_Flash.FlashData.Gateway_IP_1[0];
|
||||
W5500_1.Gateway_IP[1]=Usr_Flash.FlashData.Gateway_IP_1[1];
|
||||
W5500_1.Gateway_IP[2]=Usr_Flash.FlashData.Gateway_IP_1[2];
|
||||
W5500_1.Gateway_IP[3]=Usr_Flash.FlashData.Gateway_IP_1[3];
|
||||
|
||||
W5500_1.W5500_Class[0].ConfigData.Port[0] = Usr_Flash.FlashData.Port_1[0];
|
||||
W5500_1.W5500_Class[0].ConfigData.Port[1] = Usr_Flash.FlashData.Port_1[1];
|
||||
|
||||
W5500_1.Sub_Mask[0] = Usr_Flash.FlashData.Sub_Mask_1[0];
|
||||
W5500_1.Sub_Mask[1] = Usr_Flash.FlashData.Sub_Mask_1[1];
|
||||
W5500_1.Sub_Mask[2] = Usr_Flash.FlashData.Sub_Mask_1[2];
|
||||
W5500_1.Sub_Mask[3] = Usr_Flash.FlashData.Sub_Mask_1[3];
|
||||
|
||||
/*客户端目标网络配置*/
|
||||
W5500_1.W5500_Class[0].ConfigData.DIP[0] = Usr_Flash.FlashData.IP_Addr_2[0];
|
||||
W5500_1.W5500_Class[0].ConfigData.DIP[1] = Usr_Flash.FlashData.IP_Addr_2[1];
|
||||
W5500_1.W5500_Class[0].ConfigData.DIP[2] = Usr_Flash.FlashData.IP_Addr_2[2];
|
||||
W5500_1.W5500_Class[0].ConfigData.DIP[3] = Usr_Flash.FlashData.IP_Addr_2[3];
|
||||
|
||||
W5500_1.W5500_Class[0].ConfigData.DPort[0] = Usr_Flash.FlashData.Port_2[0];
|
||||
W5500_1.W5500_Class[0].ConfigData.DPort[1] = Usr_Flash.FlashData.Port_2[1];
|
||||
|
||||
Usr_Flash.test = 0;
|
||||
|
||||
HSMS.Flash_ConfigData.Device_Id = Usr_Flash.FlashData.Devic_Id;
|
||||
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
#ifndef _BSP_FLASH_H_
|
||||
#define _BSP_FLASH_H_
|
||||
|
||||
#include "main.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/*用于判断数据是否一致*/
|
||||
u16 SN[10];
|
||||
u8 IP_Addr[4];
|
||||
u8 Gateway_IP[4];
|
||||
u8 Port[2];
|
||||
u8 Sub_Mask[4];
|
||||
u8 IP_Addr_1[4]; /*网口1*/
|
||||
u8 Gateway_IP_1[4];
|
||||
u8 Port_1[2];
|
||||
u8 Sub_Mask_1[4];
|
||||
u8 IP_Addr_2[4]; /*客户端目标IP*/
|
||||
u8 Port_2[2];
|
||||
u16 Devic_Id;
|
||||
u16 Devic_Id_1;
|
||||
u16 Device_ID[12]; // 20字符,设备型号(20字节)
|
||||
u16 Device_Model[12]; // 18字符,报警机台和位置(20字节)
|
||||
u16 Device_SN[12]; //设备SN号
|
||||
u16 Station_Name[12]; // 机台名称
|
||||
u16 Chamber_Name[12]; // 腔体名称
|
||||
u16 Manufacturer[12]; //厂商名称
|
||||
u16 Version[12]; //机台软件版本号
|
||||
u16 Station_Type[12]; //机台类型
|
||||
|
||||
|
||||
u16 Alarm_info[20]; //使用PM100中的
|
||||
u16 Data_ID1; //置空
|
||||
u32 Collection_event_ID1; //CEID为固定值
|
||||
u32 Report_ID1; //置空
|
||||
u32 Alarm_ID; //使用函数内部的
|
||||
u16 Alarm_Type[7]; // 使用函数内部
|
||||
u16 Begin_Warning[7]; //函数内部固定为begin
|
||||
u16 IDS[11]; //置空
|
||||
u16 Over_Trigger[9];
|
||||
u16 Equipment[5];
|
||||
u16 E9[19];
|
||||
u16 Device_Type; //置空
|
||||
u16 Sensor;
|
||||
u16 Alarm_value;
|
||||
u16 Alarm_ubit;
|
||||
u16 Start_Time[11]; //开始时间
|
||||
u16 Alarm_Time[6]; //报警时长
|
||||
u16 Alarm[6]; //报警类型 策略报警、机台报警
|
||||
u16 Data_ID2;
|
||||
u16 Collection_event_ID2;
|
||||
u16 Report_ID2;
|
||||
u16 Sub_Device_Type[2]; // 附属设备类型
|
||||
u16 Sub_Device_State[2]; // 附属设备状态
|
||||
u16 State_Change_Time[2]; // 状态切换时间格式
|
||||
} bsp_FlashData_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
bsp_FlashData_t TempFlashData;
|
||||
bsp_FlashData_t FlashData;
|
||||
u8 test;
|
||||
void (*Init)(void);
|
||||
void (*Write)(void);
|
||||
void (*Read)(void);
|
||||
void (*Reset)(void);
|
||||
} bsp_Flash_t;
|
||||
|
||||
extern bsp_Flash_t Usr_Flash;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,39 @@
|
||||
#include "bsp_Key.h"
|
||||
#include "os_timer.h"
|
||||
#include "bsp_Flash.h"
|
||||
|
||||
#define BSP_KEY_ENTER_NUM 500
|
||||
|
||||
static void bsp_key_init(void);
|
||||
static void bsp_key_task(void);
|
||||
|
||||
bsp_key_t key =
|
||||
{
|
||||
.init = bsp_key_init,
|
||||
.task = bsp_key_task,
|
||||
};
|
||||
|
||||
static bsp_key_t *p_key = &key;
|
||||
|
||||
static void bsp_key_init(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static void bsp_key_task(void)
|
||||
{
|
||||
if(GPIO_PIN_RESET == HAL_GPIO_ReadPin(SYS_RESET_GPIO_Port,SYS_RESET_Pin))
|
||||
{
|
||||
p_key->count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
p_key->count = 0;
|
||||
}
|
||||
if(BSP_KEY_ENTER_NUM <= p_key->count)
|
||||
{
|
||||
/*ϵͳ¸´Î»*/
|
||||
Usr_Flash.Reset();
|
||||
HAL_NVIC_SystemReset();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
#ifndef _BSP_KEY_H_
|
||||
#define _BSP_KEY_H_
|
||||
|
||||
#include "main.h"
|
||||
typedef struct
|
||||
{
|
||||
u16 count;
|
||||
void (*init)(void);
|
||||
void (*task)(void);
|
||||
}bsp_key_t;
|
||||
extern bsp_key_t key;
|
||||
#endif
|
||||
@@ -0,0 +1,15 @@
|
||||
#ifndef _BSP_LED_H_
|
||||
#define _BSP_LED_H_
|
||||
|
||||
#include "main.h"
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void (*Init)(void);
|
||||
void (*Flash)(void);
|
||||
}bsp_Led_t;
|
||||
|
||||
extern bsp_Led_t Led;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,48 @@
|
||||
#include "bsp_Led.h"
|
||||
#include "os_timer.h"
|
||||
|
||||
#include "bsp_Flash.h"
|
||||
|
||||
#include "proto_modbus_tcp_master.h"
|
||||
|
||||
static void bsp_Led_Init(void);
|
||||
static void bsp_Led_Flash(void);
|
||||
|
||||
bsp_Led_t Led =
|
||||
{
|
||||
.Init = bsp_Led_Init,
|
||||
.Flash = bsp_Led_Flash,
|
||||
};
|
||||
/*其他外设初始化后快速闪烁,提示初始化完成*/
|
||||
static void bsp_Led_Init(void)
|
||||
{
|
||||
for(u8 i = 0;i < 20;i++)
|
||||
{
|
||||
Delay_ms(50);
|
||||
HAL_GPIO_TogglePin(LED_RUN_GPIO_Port, LED_RUN_Pin);
|
||||
}
|
||||
}
|
||||
|
||||
static void bsp_Led_Flash(void)
|
||||
{
|
||||
if (modbus_tcp.alarm_ctx.offline)
|
||||
{
|
||||
HAL_GPIO_TogglePin(LED_ERROR_GPIO_Port, LED_ERROR_Pin);
|
||||
HAL_GPIO_WritePin(LED_RUN_GPIO_Port,LED_RUN_Pin,GPIO_PIN_SET);
|
||||
}else
|
||||
{
|
||||
HAL_GPIO_TogglePin(LED_RUN_GPIO_Port, LED_RUN_Pin);
|
||||
HAL_GPIO_WritePin(LED_ERROR_GPIO_Port,LED_ERROR_Pin,GPIO_PIN_SET);
|
||||
}
|
||||
/*进入测试模式*/
|
||||
if(Usr_Flash.test == 1)
|
||||
{
|
||||
//运行和故障灯交替运行
|
||||
Delay_ms(50);
|
||||
HAL_GPIO_TogglePin(LED_RUN_GPIO_Port, LED_RUN_Pin);
|
||||
Delay_ms(50);
|
||||
HAL_GPIO_TogglePin(LED_ERROR_GPIO_Port, LED_ERROR_Pin);
|
||||
}
|
||||
|
||||
// HAL_GPIO_TogglePin(LED_RUN_GPIO_Port, LED_RUN_Pin);
|
||||
}
|
||||
@@ -0,0 +1,338 @@
|
||||
#include "bsp_Uart.h"
|
||||
|
||||
#include "string.h"
|
||||
|
||||
#define RS485_RX //HAL_GPIO_WritePin(RS485_EN_GPIO_Port, RS485_EN_Pin, GPIO_PIN_RESET)
|
||||
#define RS485_TX //HAL_GPIO_WritePin(RS485_EN_GPIO_Port, RS485_EN_Pin, GPIO_PIN_SET)
|
||||
|
||||
|
||||
/*缓冲收发区*/
|
||||
#define RX_TEMP_BUFF_NUM (512U)
|
||||
u8 Rx_Temp_Buff[RX_TEMP_BUFF_NUM];
|
||||
|
||||
#define UART1_TX_LEN (256U)
|
||||
#define UART1_RX_LEN (256U)
|
||||
|
||||
#define UART2_TX_LEN (256U)
|
||||
#define UART2_RX_LEN (256U)
|
||||
|
||||
#define UART3_TX_LEN (512U)
|
||||
#define UART3_RX_LEN (512U)
|
||||
|
||||
|
||||
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];
|
||||
|
||||
static void bsp_Uart_Init(bsp_Uart_t *p_Uart);
|
||||
static void bsp_Uart_Send(bsp_Uart_t *p_Uart,u8 *pData, u16 Len);
|
||||
static void bsp_Uart_Rx_IdleInt(bsp_Uart_t *p_Uart);
|
||||
static void bsp_Uart_Rx_TimeIncrement(bsp_Uart_t *p_Uart,u16 Time);
|
||||
static void bsp_Uart_Rx_Task(bsp_Uart_t *p_Uart);
|
||||
static void bsp_Uart_Rx_TimeStart(bsp_Uart_t *p_Uart);
|
||||
static void bsp_Uart_Tx_DMA_TCInt(bsp_Uart_t *p_Uart);
|
||||
|
||||
extern UART_HandleTypeDef huart1;
|
||||
extern UART_HandleTypeDef huart2;
|
||||
extern UART_HandleTypeDef huart3;
|
||||
|
||||
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;
|
||||
|
||||
bsp_Uart_t COM_Uart1 =
|
||||
{
|
||||
.RxQueue = 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_CompleteFlag = 1,
|
||||
.Rx_TimeOver = 10,
|
||||
|
||||
.Init = bsp_Uart_Init,
|
||||
.Send = bsp_Uart_Send,
|
||||
|
||||
.Tx_DMA_TCInt = bsp_Uart_Tx_DMA_TCInt,
|
||||
.Rx_IdleInt = bsp_Uart_Rx_IdleInt,
|
||||
.Rx_TimeIncrementInt = bsp_Uart_Rx_TimeIncrement,
|
||||
.Rx_DataAnalysis = NULL,
|
||||
.Rx_Task = bsp_Uart_Rx_Task,
|
||||
};
|
||||
|
||||
bsp_Uart_t COM_Uart2 =
|
||||
{
|
||||
.RxQueue = 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_CompleteFlag = 1,
|
||||
.Rx_TimeOver = 10,
|
||||
|
||||
.Init = bsp_Uart_Init,
|
||||
.Send = bsp_Uart_Send,
|
||||
.Tx_DMA_TCInt = bsp_Uart_Tx_DMA_TCInt,
|
||||
.Rx_IdleInt = bsp_Uart_Rx_IdleInt,
|
||||
.Rx_TimeIncrementInt = bsp_Uart_Rx_TimeIncrement,
|
||||
.Rx_DataAnalysis = NULL,
|
||||
.Rx_Task = bsp_Uart_Rx_Task,
|
||||
};
|
||||
|
||||
bsp_Uart_t COM_Uart3 =
|
||||
{
|
||||
.RxQueue = 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_CompleteFlag = 1,
|
||||
.Rx_TimeOver = 10,
|
||||
|
||||
.Init = bsp_Uart_Init,
|
||||
.Send = bsp_Uart_Send,
|
||||
.Tx_DMA_TCInt = bsp_Uart_Tx_DMA_TCInt,
|
||||
.Rx_IdleInt = bsp_Uart_Rx_IdleInt,
|
||||
.Rx_TimeIncrementInt = bsp_Uart_Rx_TimeIncrement,
|
||||
.Rx_DataAnalysis = NULL,
|
||||
.Rx_Task = bsp_Uart_Rx_Task,
|
||||
};
|
||||
|
||||
|
||||
/* 初始化函数 */
|
||||
static void bsp_Uart_Init(bsp_Uart_t *p_Uart)
|
||||
{
|
||||
/*配置数据解析函数*/
|
||||
//p_Uart->Rx_DataAnalysis = NULL;
|
||||
|
||||
/* 启用空闲中断 */
|
||||
__HAL_UART_ENABLE_IT(p_Uart->Uart, UART_IT_IDLE);
|
||||
|
||||
/* 启动DMA接收 */
|
||||
HAL_UART_Receive_DMA(p_Uart->Uart, p_Uart->Rx_Addr, p_Uart->Rx_DMA_Len);
|
||||
}
|
||||
|
||||
|
||||
/* 判断DMA发送是否完成 */
|
||||
static uint8_t bsp_Uart_IsDMATxComplete(bsp_Uart_t *p_Uart)
|
||||
{
|
||||
// 方法1.1: 检查DMA状态
|
||||
if (HAL_DMA_GetState(p_Uart->Tx_DMA) == HAL_DMA_STATE_READY) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// // 方法1.2: 检查UART状态
|
||||
// if (HAL_UART_GetState(p_Uart->Uart) == HAL_UART_STATE_READY) {
|
||||
// return 1;
|
||||
// }
|
||||
//
|
||||
// 方法1.3: 检查DMA传输计数器
|
||||
if (__HAL_DMA_GET_COUNTER(p_Uart->Tx_DMA) == 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void bsp_Uart_DMASend(bsp_Uart_t *p_Uart,u8 *pData, u16 Len)
|
||||
{
|
||||
while( !p_Uart->Tx_DMA_CompleteFlag)
|
||||
{
|
||||
|
||||
}
|
||||
p_Uart->Tx_DMA_CompleteFlag = 0;
|
||||
if(p_Uart->Tx_DMA_Len < Len)
|
||||
Len = p_Uart->Tx_DMA_Len;
|
||||
memcpy(p_Uart->Tx_Addr, pData, Len); /*拷贝数据到发送缓冲*/
|
||||
|
||||
HAL_UART_Transmit_DMA(p_Uart->Uart,p_Uart->Tx_Addr,Len);
|
||||
// while (!bsp_Uart_IsDMATxComplete(p_Uart)); /*等待传输完成标志*/
|
||||
// //传输是否完成
|
||||
//
|
||||
// while (HAL_UART_GetState(&huart1) == HAL_UART_STATE_BUSY_TX) {
|
||||
// // 短暂延时,避免忙等
|
||||
// }
|
||||
}
|
||||
|
||||
/*大数据量发送*/
|
||||
static void bsp_Uart_Send(bsp_Uart_t *p_Uart,u8 *pData, u16 Len)
|
||||
{
|
||||
u16 i,SendNum;
|
||||
|
||||
if(p_Uart->Uart == &huart1)
|
||||
RS485_TX;
|
||||
SendNum = Len / p_Uart->Tx_DMA_Len;
|
||||
for(i=0;i<SendNum;i++)
|
||||
{
|
||||
bsp_Uart_DMASend(p_Uart,&pData[p_Uart->Tx_DMA_Len * i], p_Uart->Tx_DMA_Len);
|
||||
}
|
||||
|
||||
/*发送剩余数据*/
|
||||
Len -= p_Uart->Tx_DMA_Len * i;
|
||||
if(0 == Len)
|
||||
{
|
||||
return ;
|
||||
}
|
||||
else
|
||||
{
|
||||
bsp_Uart_DMASend(p_Uart,&pData[p_Uart->Tx_DMA_Len * i],Len);
|
||||
}
|
||||
}
|
||||
|
||||
static void bsp_Uart_Tx_DMA_TCInt(bsp_Uart_t *p_Uart)
|
||||
{
|
||||
p_Uart->Tx_DMA_CompleteFlag = 1;
|
||||
}
|
||||
|
||||
/*空闲接收中断*/
|
||||
static void bsp_Uart_Rx_IdleInt(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->RxQueue, (void *)&p_Uart->Rx_Addr[i]);
|
||||
}
|
||||
|
||||
/* 开始计数 */
|
||||
bsp_Uart_Rx_TimeStart(p_Uart);
|
||||
|
||||
/* 重新启动DMA接收 */
|
||||
HAL_UART_Receive_DMA(p_Uart->Uart, p_Uart->Rx_Addr, p_Uart->Rx_DMA_Len);
|
||||
}
|
||||
|
||||
/*中断计数*/
|
||||
static void bsp_Uart_Rx_TimeIncrement(bsp_Uart_t *p_Uart,u16 Time)
|
||||
{
|
||||
/*开始计数*/
|
||||
if(1 == p_Uart->Rx_StartFlag)
|
||||
{
|
||||
p_Uart->Rx_TimeCount += Time;
|
||||
}
|
||||
}
|
||||
|
||||
/*开始计数*/
|
||||
static void bsp_Uart_Rx_TimeStart(bsp_Uart_t *p_Uart)
|
||||
{
|
||||
p_Uart->Rx_StartFlag = 1;
|
||||
p_Uart->Rx_TimeCount = 0;
|
||||
}
|
||||
|
||||
/*停止计数*/
|
||||
static void bsp_Uart_Rx_TimeStop(bsp_Uart_t *p_Uart)
|
||||
{
|
||||
p_Uart->Rx_StartFlag = 0;
|
||||
p_Uart->Rx_TimeCount = 0;
|
||||
}
|
||||
|
||||
static void bsp_Uart_Rx_Task(bsp_Uart_t *p_Uart)
|
||||
{
|
||||
/*超时计数完成,接收到一帧数据*/
|
||||
if(p_Uart->Rx_TimeOver < p_Uart->Rx_TimeCount)
|
||||
{
|
||||
p_Uart->Rx_Len = queue_size(p_Uart->RxQueue);
|
||||
/*停止计数*/
|
||||
bsp_Uart_Rx_TimeStop(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->RxQueue);
|
||||
}
|
||||
else
|
||||
{
|
||||
for(u16 i = 0;i < p_Uart->Rx_Len;i++)
|
||||
{
|
||||
queue_pop(p_Uart->RxQueue,&Rx_Temp_Buff[i]);
|
||||
}
|
||||
if(NULL != p_Uart->Rx_DataAnalysis)
|
||||
{
|
||||
p_Uart->Rx_DataAnalysis(Rx_Temp_Buff,p_Uart->Rx_Len,p_Uart); /*解析数据*/
|
||||
}
|
||||
//p_Uart->Send(p_Uart,Rx_Temp_Buff,p_Uart->Rx_Len);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///* 串口接收完成回调函数 - 处理空闲中断 */
|
||||
//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 == USART3)
|
||||
// {
|
||||
// bsp_Uart_Rx_IdleInt(&COM_Uart3);
|
||||
// }
|
||||
// else if (huart->Instance == UART4)
|
||||
// {
|
||||
// bsp_Uart_Rx_IdleInt(&COM_Uart4);
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
|
||||
{
|
||||
if (huart->Instance == USART1)
|
||||
{
|
||||
RS485_RX;
|
||||
COM_Uart1.Tx_DMA_TCInt(&COM_Uart1);
|
||||
}
|
||||
else if (huart->Instance == USART2)
|
||||
{
|
||||
COM_Uart2.Tx_DMA_TCInt(&COM_Uart2);
|
||||
}
|
||||
else if (huart->Instance == USART3)
|
||||
{
|
||||
COM_Uart3.Tx_DMA_TCInt(&COM_Uart3);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
#ifndef _BSP_UART_H_
|
||||
#define _BSP_UART_H_
|
||||
|
||||
#include "main.h"
|
||||
#include "algo_Queue.h"
|
||||
|
||||
typedef struct bsp_Uart_t bsp_Uart_t;
|
||||
|
||||
|
||||
#define usart_type UART_HandleTypeDef
|
||||
#define dma_type DMA_HandleTypeDef
|
||||
|
||||
struct bsp_Uart_t
|
||||
{
|
||||
queue RxQueue; /*数据接收队列*/
|
||||
usart_type *Uart; /*串口*/
|
||||
|
||||
dma_type *Tx_DMA; /*DMA*/
|
||||
dma_type *Rx_DMA;
|
||||
|
||||
u8 Tx_DMA_CH;
|
||||
u8 Rx_DMA_CH;
|
||||
vu8 Tx_DMA_CompleteFlag; /*DMA接受完成标志位*/
|
||||
|
||||
u8 *Tx_Addr; /*DMA搬运缓冲*/
|
||||
u8 *Rx_Addr;
|
||||
u16 Tx_DMA_Len;
|
||||
u16 Rx_DMA_Len;
|
||||
|
||||
u16 Rx_Len; /*接收到的数据长度*/
|
||||
u16 Rx_TimeCount; /*超时计数*/
|
||||
u16 Rx_TimeOver; /*超时时间*/
|
||||
u8 Rx_StartFlag; /*开始超时计数标志位*/
|
||||
|
||||
void (*Init)(bsp_Uart_t *); /*初始化*/
|
||||
void (*Send)(bsp_Uart_t *,u8 *,u16); /*串口发送函数*/
|
||||
|
||||
void (*Tx_DMA_TCInt)(bsp_Uart_t *); /*DMA发送完成中断*/
|
||||
|
||||
void (*Rx_IdleInt)(bsp_Uart_t *); /*空闲中断*/
|
||||
void (*Rx_TimeIncrementInt)(bsp_Uart_t *,u16); /*中断计数计数*/
|
||||
void (*Rx_DataAnalysis)(u8 *,u16,void *other_data); /*数据解析*/
|
||||
void (*Rx_Task)(bsp_Uart_t *); /*串口接收任务*/
|
||||
|
||||
};
|
||||
|
||||
extern bsp_Uart_t COM_Uart1;
|
||||
extern bsp_Uart_t COM_Uart2;
|
||||
extern bsp_Uart_t COM_Uart3;
|
||||
#endif
|
||||
@@ -0,0 +1,868 @@
|
||||
/**********************************************************************************
|
||||
* 文件名 :W5500.c
|
||||
* 描述 :W5500 驱动函数库
|
||||
* 库版本 :ST_v3.5
|
||||
* 作者 :泥人通信模块开发团队
|
||||
* 博客 :http://nirenelec.blog.163.com
|
||||
* 淘宝 :http://nirenelec.taobao.com
|
||||
**********************************************************************************/
|
||||
|
||||
#include "stm32f1xx.h"
|
||||
#include "stm32f1xx_hal_spi.h"
|
||||
|
||||
#include "bsp_W5500.h"
|
||||
#include "usart.h"
|
||||
#include "stdio.h"
|
||||
#include "spi.h"
|
||||
#include "bsp_print.h"
|
||||
#include "bsp_Wdg.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(广播)模式*/
|
||||
|
||||
|
||||
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);
|
||||
static void network_monitor_task(void);
|
||||
void bsp_W5500_Socket_Set(bsp_W5500_Class_t *pW5500_Class);
|
||||
|
||||
static u8 last_link_status = 0; // 保存上一次链路状态
|
||||
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,1,101},
|
||||
.Monitor_task = network_monitor_task,
|
||||
.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.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:待发送的数据
|
||||
* 输出 : 无
|
||||
* 返回值 : 无
|
||||
* 说明 : 无
|
||||
*******************************************************************************/
|
||||
static 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位数据
|
||||
* 输出 : 无
|
||||
* 返回值 : 无
|
||||
* 说明 : 无
|
||||
*******************************************************************************/
|
||||
static void SPI1_Send_Short(u16 dat)
|
||||
{
|
||||
SPI1_Send_Byte(dat >> 8); // 写数据高位
|
||||
SPI1_Send_Byte(dat); // 写数据低位
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* 函数名 : Write_W5500_1Byte
|
||||
* 描述 : 通过SPI1向指定地址寄存器写1个字节数据
|
||||
* 输入 : reg:16位寄存器地址,dat:待写入的数据
|
||||
* 输出 : 无
|
||||
* 返回值 : 无
|
||||
* 说明 : 无
|
||||
*******************************************************************************/
|
||||
static 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)
|
||||
{
|
||||
#define STM32F1_UID_BASE 0x1FFFF7E8
|
||||
u16 i = 0;
|
||||
u32 uid[3] = {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个字节为厂商代码,后三个字节为产品序号
|
||||
// 如果自己定义物理地址,注意第一个字节必须为偶数
|
||||
// 设置物理地址,PHY_ADDR为6字节u8数组,自己定义,用于唯一标识网络设备的物理地址值
|
||||
// 该地址值需要到IEEE申请,按照OUI的规定,前3个字节为厂商代码,后三个字节为产品序号
|
||||
// 如果自己定义物理地址,注意第一个字节必须为偶数
|
||||
//使用单片机UID
|
||||
|
||||
uid[0] = *(u32*)(STM32F1_UID_BASE);
|
||||
uid[1] = *(u32*)(STM32F1_UID_BASE + 4);
|
||||
uid[2] = *(u32*)(STM32F1_UID_BASE + 8);
|
||||
|
||||
|
||||
pW5500->Phy_Addr[0] = uid[1] >> 8;
|
||||
pW5500->Phy_Addr[1] = uid[1];
|
||||
pW5500->Phy_Addr[2] = uid[2] >> 24;
|
||||
pW5500->Phy_Addr[3] = uid[2] >> 16;
|
||||
pW5500->Phy_Addr[4] = uid[2] >> 8;
|
||||
pW5500->Phy_Addr[5] = uid[2];
|
||||
|
||||
// 设置本地管理位,并将单播位清零
|
||||
pW5500->Phy_Addr[0] = (pW5500->Phy_Addr[0] & 0xFE) | 0x02;
|
||||
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) {
|
||||
// 1. 清除超时中断标志位 (你的代码已有)
|
||||
Write_W5500_SOCK_1Byte(pW5500->W5500_Class[i].SocketPort, Sn_IR, Socket_Flag);
|
||||
|
||||
// 2. 强制关闭Socket,确保其状态机复位
|
||||
Write_W5500_SOCK_1Byte(pW5500->W5500_Class[i].SocketPort, Sn_CR, CLOSE);
|
||||
|
||||
// 3. (强烈推荐) 增加一小段延时,等待硬件完成关闭操作
|
||||
HAL_Delay(10);
|
||||
|
||||
// 4. 关键修复:重新打开Socket并进入监听模式
|
||||
// bsp_W5500_Socket_Init 函数用于配置Socket参数
|
||||
bsp_W5500_Socket_Init(&pW5500->W5500_Class[i]);
|
||||
// bsp_W5500_Socket_Set 函数会根据配置的模式(TCP Server)调用 Socket_Listen
|
||||
bsp_W5500_Socket_Set(&pW5500->W5500_Class[i]);
|
||||
|
||||
// 5. 清理相关的状态标志位
|
||||
pW5500->W5500_Class[i].Run_State = 0;
|
||||
pW5500->W5500_Class[i].TR_Data_State = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (Read_W5500_1Byte(SIR) != 0)
|
||||
goto IntDispose;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置指定Socket的Keep-Alive间隔
|
||||
* @param s: Socket端口号 (0~7)
|
||||
* @param interval_5s: 间隔时间,单位5秒,例如2表示10秒。0表示禁用。
|
||||
*/
|
||||
void w5500_set_keepalive(SOCKET s, uint8_t interval_5s)
|
||||
{
|
||||
Write_W5500_SOCK_1Byte(s, Sn_KPALVTR, interval_5s);
|
||||
}
|
||||
|
||||
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;
|
||||
w5500_set_keepalive(pW5500_Class->SocketPort, 2);
|
||||
}
|
||||
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;
|
||||
Wdg.Feed();
|
||||
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);/*数据解析*/
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取 W5500 物理链路状态
|
||||
* @return 1: 链路连接, 0: 链路断开
|
||||
*/
|
||||
static u8 w5500_get_link_status(void)
|
||||
{
|
||||
u8 phycfgr = Read_W5500_1Byte(PHYCFGR); // 读取 PHYCFGR 寄存器
|
||||
return (phycfgr & LINK) ? 1 : 0; // 返回 LINK 位
|
||||
}
|
||||
|
||||
|
||||
static void network_monitor_task(void)
|
||||
{
|
||||
u8 current_link = w5500_get_link_status();
|
||||
|
||||
if (last_link_status == 0 && current_link == 1) {
|
||||
/*链路从断开变为连接,执行恢复操作*/
|
||||
W5500.Init();
|
||||
}
|
||||
|
||||
last_link_status = current_link;
|
||||
}
|
||||
@@ -0,0 +1,278 @@
|
||||
#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的设置修改 */
|
||||
|
||||
/*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 /*端口发送一个数据包完成*/
|
||||
|
||||
/***************----- W5500 GPIO定义 -----***************/
|
||||
#define W5500_SCS GPIO_PIN_0 // 定义W5500的CS引脚
|
||||
#define W5500_SCS_PORT GPIOB
|
||||
|
||||
#define W5500_RST GPIO_PIN_4 // 定义W5500的RST引脚
|
||||
#define W5500_RST_PORT GPIOA
|
||||
|
||||
#define W5500_INT GPIO_PIN_1 // 定义W5500的INT引脚
|
||||
#define W5500_INT_PORT GPIOA
|
||||
|
||||
typedef u8 SOCKET; // 自定义端口号数据类型
|
||||
#define BSP_W5500_PORT_NUM 1
|
||||
|
||||
#define BSP_W5500_TX_DATA_LEN 2048
|
||||
#define BSP_W5500_RX_DATA_LEN 256
|
||||
|
||||
typedef struct bsp_W5500_Class_t bsp_W5500_Class_t;
|
||||
|
||||
struct bsp_W5500_Class_t
|
||||
{
|
||||
SOCKET SocketPort;
|
||||
struct
|
||||
{
|
||||
/***************----- 网络参数变量定义 -----***************/
|
||||
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_RX_DATA_LEN]; // 端口接收数据缓冲区
|
||||
u8 Tx_Buffer[BSP_W5500_TX_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 (*Monitor_task)(void); /*重连检测*/
|
||||
void (*Socket_Send)(bsp_W5500_Class_t *, u8 *, u16 ); /*端口发送数据*/
|
||||
}bsp_W5500_t;
|
||||
|
||||
|
||||
extern bsp_W5500_t W5500;
|
||||
#endif
|
||||
@@ -0,0 +1,870 @@
|
||||
/**********************************************************************************
|
||||
* 文件名 :W5500.c
|
||||
* 描述 :W5500 驱动函数库
|
||||
* 库版本 :ST_v3.5
|
||||
* 作者 :泥人通信模块开发团队
|
||||
* 博客 :http://nirenelec.blog.163.com
|
||||
* 淘宝 :http://nirenelec.taobao.com
|
||||
**********************************************************************************/
|
||||
|
||||
#include "stm32f1xx.h"
|
||||
#include "stm32f1xx_hal_spi.h"
|
||||
|
||||
#include "bsp_W5500_1.h"
|
||||
#include "usart.h"
|
||||
#include "stdio.h"
|
||||
#include "spi.h"
|
||||
#include "bsp_print.h"
|
||||
#include "bsp_Wdg.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_1_Class, u8 *dat_ptr, u16 size);
|
||||
static void network_monitor_task(void);
|
||||
void bsp_W5500_Socket_Set(bsp_W5500_Class_t *pW5500_1_Class);
|
||||
|
||||
static u8 last_link_status = 0; // 保存上一次链路状态
|
||||
bsp_W5500_t W5500_1 =
|
||||
{
|
||||
.Gateway_IP = {192,168,100,1},
|
||||
.Sub_Mask = {255,255,255,0},
|
||||
.Phy_Addr = {0x0c,0x29,0xab,0x7c,0x00,0x02},
|
||||
.IP_Addr = {192,168,100,103},
|
||||
.Monitor_task = network_monitor_task,
|
||||
.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.Port = {0x13,0x88}, // 本地端口 5000(可自定义)
|
||||
.ConfigData.DIP = {192,168,100,41}, // 目标服务器 IP
|
||||
.ConfigData.DPort = {0x01,0xF6}, // 目标端口 502
|
||||
.Run_Mode = BSP_W5500_PORT_RUN_MODE_TCP_CLIENT,
|
||||
},
|
||||
};
|
||||
|
||||
bsp_W5500_t *pW5500_1 = &W5500_1;
|
||||
|
||||
/*******************************************************************************
|
||||
* 函数名 : SPI2_Send_Byte
|
||||
* 描述 : SPI2发送1个字节数据
|
||||
* 输入 : dat:待发送的数据
|
||||
* 输出 : 无
|
||||
* 返回值 : 无
|
||||
* 说明 : 无
|
||||
*******************************************************************************/
|
||||
static void SPI2_Send_Byte(u8 dat)
|
||||
{
|
||||
// hspi2.Instance->DR=dat;
|
||||
HAL_SPI_Transmit(&hspi2, &dat, 1, 0xff);
|
||||
// while(__HAL_SPI_GET_FLAG(&hspi2,SPI_FLAG_TXE)==RESET);
|
||||
// SPI_I2S_SendData(SPI2,dat);//写1个字节数据
|
||||
// while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET);//等待数据寄存器空
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* 函数名 : SPI2_Send_Short
|
||||
* 描述 : SPI2发送2个字节数据(16位)
|
||||
* 输入 : dat:待发送的16位数据
|
||||
* 输出 : 无
|
||||
* 返回值 : 无
|
||||
* 说明 : 无
|
||||
*******************************************************************************/
|
||||
static void SPI2_Send_Short(u16 dat)
|
||||
{
|
||||
SPI2_Send_Byte(dat >> 8); // 写数据高位
|
||||
SPI2_Send_Byte(dat); // 写数据低位
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* 函数名 : Write_W5500_1Byte
|
||||
* 描述 : 通过SPI2向指定地址寄存器写1个字节数据
|
||||
* 输入 : reg:16位寄存器地址,dat:待写入的数据
|
||||
* 输出 : 无
|
||||
* 返回值 : 无
|
||||
* 说明 : 无
|
||||
*******************************************************************************/
|
||||
static void Write_W5500_1Byte(u16 reg, u8 dat)
|
||||
{
|
||||
HAL_GPIO_WritePin(W5500_1_SCS_PORT, W5500_1_SCS_PIN, GPIO_PIN_RESET); // 置W5500的SCS为低电平
|
||||
|
||||
SPI2_Send_Short(reg); // 通过SPI2写16位寄存器地址
|
||||
SPI2_Send_Byte(FDM1 | RWB_WRITE | COMMON_R); // 通过SPI2写控制字节,1个字节数据长度,写数据,选择通用寄存器
|
||||
SPI2_Send_Byte(dat); // 写1个字节数据
|
||||
|
||||
HAL_GPIO_WritePin(W5500_1_SCS_PORT, W5500_1_SCS_PIN, GPIO_PIN_SET); // 置W5500的SCS为高电平
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* 函数名 : Write_W5500_2Byte
|
||||
* 描述 : 通过SPI2向指定地址寄存器写2个字节数据
|
||||
* 输入 : reg:16位寄存器地址,dat:16位待写入的数据(2个字节)
|
||||
* 输出 : 无
|
||||
* 返回值 : 无
|
||||
* 说明 : 无
|
||||
*******************************************************************************/
|
||||
static void Write_W5500_2Byte(u16 reg, u16 dat)
|
||||
{
|
||||
HAL_GPIO_WritePin(W5500_1_SCS_PORT, W5500_1_SCS_PIN, GPIO_PIN_RESET); // 置W5500的SCS为低电平
|
||||
|
||||
SPI2_Send_Short(reg); // 通过SPI2写16位寄存器地址
|
||||
SPI2_Send_Byte(FDM2 | RWB_WRITE | COMMON_R); // 通过SPI2写控制字节,2个字节数据长度,写数据,选择通用寄存器
|
||||
SPI2_Send_Short(dat); // 写16位数据
|
||||
|
||||
HAL_GPIO_WritePin(W5500_1_SCS_PORT, W5500_1_SCS_PIN, GPIO_PIN_SET); // 置W5500的SCS为高电平
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* 函数名 : Write_W5500_nByte
|
||||
* 描述 : 通过SPI2向指定地址寄存器写n个字节数据
|
||||
* 输入 : reg:16位寄存器地址,*dat_ptr:待写入数据缓冲区指针,size:待写入的数据长度
|
||||
* 输出 : 无
|
||||
* 返回值 : 无
|
||||
* 说明 : 无
|
||||
*******************************************************************************/
|
||||
static void Write_W5500_nByte(u16 reg, u8 *dat_ptr, u16 size)
|
||||
{
|
||||
u16 i;
|
||||
|
||||
HAL_GPIO_WritePin(W5500_1_SCS_PORT, W5500_1_SCS_PIN, GPIO_PIN_RESET); // 置W5500的SCS为低电平
|
||||
|
||||
SPI2_Send_Short(reg); // 通过SPI2写16位寄存器地址
|
||||
SPI2_Send_Byte(VDM | RWB_WRITE | COMMON_R); // 通过SPI2写控制字节,N个字节数据长度,写数据,选择通用寄存器
|
||||
|
||||
for (i = 0; i < size; i++) // 循环将缓冲区的size个字节数据写入W5500
|
||||
{
|
||||
SPI2_Send_Byte(*dat_ptr++); // 写一个字节数据
|
||||
}
|
||||
|
||||
HAL_GPIO_WritePin(W5500_1_SCS_PORT, W5500_1_SCS_PIN, GPIO_PIN_SET); // 置W5500的SCS为高电平
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* 函数名 : Write_W5500_SOCK_1Byte
|
||||
* 描述 : 通过SPI2向指定端口寄存器写1个字节数据
|
||||
* 输入 : s:端口号,reg:16位寄存器地址,dat:待写入的数据
|
||||
* 输出 : 无
|
||||
* 返回值 : 无
|
||||
* 说明 : 无
|
||||
*******************************************************************************/
|
||||
static void Write_W5500_SOCK_1Byte(SOCKET s, u16 reg, u8 dat)
|
||||
{
|
||||
HAL_GPIO_WritePin(W5500_1_SCS_PORT, W5500_1_SCS_PIN, GPIO_PIN_RESET); // 置W5500的SCS为低电平
|
||||
|
||||
SPI2_Send_Short(reg); // 通过SPI2写16位寄存器地址
|
||||
SPI2_Send_Byte(FDM1 | RWB_WRITE | (s * 0x20 + 0x08)); // 通过SPI2写控制字节,1个字节数据长度,写数据,选择端口s的寄存器
|
||||
SPI2_Send_Byte(dat); // 写1个字节数据
|
||||
|
||||
HAL_GPIO_WritePin(W5500_1_SCS_PORT, W5500_1_SCS_PIN, GPIO_PIN_SET); // 置W5500的SCS为高电平
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* 函数名 : Write_W5500_SOCK_2Byte
|
||||
* 描述 : 通过SPI2向指定端口寄存器写2个字节数据
|
||||
* 输入 : s:端口号,reg:16位寄存器地址,dat:16位待写入的数据(2个字节)
|
||||
* 输出 : 无
|
||||
* 返回值 : 无
|
||||
* 说明 : 无
|
||||
*******************************************************************************/
|
||||
static void Write_W5500_SOCK_2Byte(SOCKET s, u16 reg, u16 dat)
|
||||
{
|
||||
HAL_GPIO_WritePin(W5500_1_SCS_PORT, W5500_1_SCS_PIN, GPIO_PIN_RESET); // 置W5500的SCS为低电平
|
||||
|
||||
SPI2_Send_Short(reg); // 通过SPI2写16位寄存器地址
|
||||
SPI2_Send_Byte(FDM2 | RWB_WRITE | (s * 0x20 + 0x08)); // 通过SPI2写控制字节,2个字节数据长度,写数据,选择端口s的寄存器
|
||||
SPI2_Send_Short(dat); // 写16位数据
|
||||
|
||||
HAL_GPIO_WritePin(W5500_1_SCS_PORT, W5500_1_SCS_PIN, GPIO_PIN_SET); // 置W5500的SCS为高电平
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* 函数名 : Write_W5500_SOCK_4Byte
|
||||
* 描述 : 通过SPI2向指定端口寄存器写4个字节数据
|
||||
* 输入 : s:端口号,reg:16位寄存器地址,*dat_ptr:待写入的4个字节缓冲区指针
|
||||
* 输出 : 无
|
||||
* 返回值 : 无
|
||||
* 说明 : 无
|
||||
*******************************************************************************/
|
||||
static void Write_W5500_SOCK_4Byte(SOCKET s, u16 reg, u8 *dat_ptr)
|
||||
{
|
||||
HAL_GPIO_WritePin(W5500_1_SCS_PORT, W5500_1_SCS_PIN, GPIO_PIN_RESET); // 置W5500的SCS为低电平
|
||||
|
||||
SPI2_Send_Short(reg); // 通过SPI2写16位寄存器地址
|
||||
SPI2_Send_Byte(FDM4 | RWB_WRITE | (s * 0x20 + 0x08)); // 通过SPI2写控制字节,4个字节数据长度,写数据,选择端口s的寄存器
|
||||
|
||||
SPI2_Send_Byte(*dat_ptr++); // 写第1个字节数据
|
||||
SPI2_Send_Byte(*dat_ptr++); // 写第2个字节数据
|
||||
SPI2_Send_Byte(*dat_ptr++); // 写第3个字节数据
|
||||
SPI2_Send_Byte(*dat_ptr++); // 写第4个字节数据
|
||||
|
||||
HAL_GPIO_WritePin(W5500_1_SCS_PORT, W5500_1_SCS_PIN, GPIO_PIN_SET); // 置W5500的SCS为高电平
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* 函数名 : Read_W5500_1Byte
|
||||
* 描述 : 读W5500指定地址寄存器的1个字节数据
|
||||
* 输入 : reg:16位寄存器地址
|
||||
* 输出 : 无
|
||||
* 返回值 : 读取到寄存器的1个字节数据
|
||||
* 说明 : 无
|
||||
*******************************************************************************/
|
||||
static u8 Read_W5500_1Byte(u16 reg)
|
||||
{
|
||||
u8 i;
|
||||
|
||||
HAL_GPIO_WritePin(W5500_1_SCS_PORT, W5500_1_SCS_PIN, GPIO_PIN_RESET); // 置W5500的SCS为低电平
|
||||
|
||||
SPI2_Send_Short(reg); // 通过SPI2写16位寄存器地址
|
||||
SPI2_Send_Byte(FDM1 | RWB_READ | COMMON_R); // 通过SPI2写控制字节,1个字节数据长度,读数据,选择通用寄存器
|
||||
i = hspi2.Instance->DR;
|
||||
// HAL_SPI_Receive(&hspi2,&i,1,0xf);
|
||||
// i=SPI_I2S_ReceiveData(SPI2);
|
||||
SPI2_Send_Byte(0x00); // 发送一个哑数据
|
||||
|
||||
i = hspi2.Instance->DR;
|
||||
// HAL_SPI_Receive(&hspi2,&i,1,0xf);
|
||||
|
||||
// i=SPI_I2S_ReceiveData(SPI2);//读取1个字节数据
|
||||
|
||||
HAL_GPIO_WritePin(W5500_1_SCS_PORT, W5500_1_SCS_PIN, GPIO_PIN_SET); // 置W5500的SCS为高电平
|
||||
return i; // 返回读取到的寄存器数据
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* 函数名 : Read_W5500_SOCK_1Byte
|
||||
* 描述 : 读W5500指定端口寄存器的1个字节数据
|
||||
* 输入 : s:端口号,reg:16位寄存器地址
|
||||
* 输出 : 无
|
||||
* 返回值 : 读取到寄存器的1个字节数据
|
||||
* 说明 : 无
|
||||
*******************************************************************************/
|
||||
static u8 Read_W5500_SOCK_1Byte(SOCKET s, u16 reg)
|
||||
{
|
||||
u8 i;
|
||||
|
||||
HAL_GPIO_WritePin(W5500_1_SCS_PORT, W5500_1_SCS_PIN, GPIO_PIN_RESET); // 置W5500的SCS为低电平
|
||||
|
||||
SPI2_Send_Short(reg); // 通过SPI2写16位寄存器地址
|
||||
SPI2_Send_Byte(FDM1 | RWB_READ | (s * 0x20 + 0x08)); // 通过SPI2写控制字节,1个字节数据长度,读数据,选择端口s的寄存器
|
||||
|
||||
i = hspi2.Instance->DR;
|
||||
// i=SPI_I2S_ReceiveData(SPI2);
|
||||
SPI2_Send_Byte(0x00); // 发送一个哑数据
|
||||
i = hspi2.Instance->DR;
|
||||
// i=SPI_I2S_ReceiveData(SPI2);//读取1个字节数据
|
||||
|
||||
HAL_GPIO_WritePin(W5500_1_SCS_PORT, W5500_1_SCS_PIN, GPIO_PIN_SET); // 置W5500的SCS为高电平
|
||||
return i; // 返回读取到的寄存器数据
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* 函数名 : Read_W5500_SOCK_2Byte
|
||||
* 描述 : 读W5500指定端口寄存器的2个字节数据
|
||||
* 输入 : s:端口号,reg:16位寄存器地址
|
||||
* 输出 : 无
|
||||
* 返回值 : 读取到寄存器的2个字节数据(16位)
|
||||
* 说明 : 无
|
||||
*******************************************************************************/
|
||||
static u16 Read_W5500_SOCK_2Byte(SOCKET s, u16 reg)
|
||||
{
|
||||
u16 i;
|
||||
|
||||
HAL_GPIO_WritePin(W5500_1_SCS_PORT, W5500_1_SCS_PIN, GPIO_PIN_RESET); // 置W5500的SCS为低电平
|
||||
|
||||
SPI2_Send_Short(reg); // 通过SPI2写16位寄存器地址
|
||||
SPI2_Send_Byte(FDM2 | RWB_READ | (s * 0x20 + 0x08)); // 通过SPI2写控制字节,2个字节数据长度,读数据,选择端口s的寄存器
|
||||
|
||||
i = hspi2.Instance->DR;
|
||||
// i=SPI_I2S_ReceiveData(SPI2);
|
||||
SPI2_Send_Byte(0x00); // 发送一个哑数据
|
||||
i = hspi2.Instance->DR;
|
||||
// i=SPI_I2S_ReceiveData(SPI2);//读取高位数据
|
||||
SPI2_Send_Byte(0x00); // 发送一个哑数据
|
||||
i *= 256;
|
||||
i += hspi2.Instance->DR;
|
||||
// i+=SPI_I2S_ReceiveData(SPI2);//读取低位数据
|
||||
|
||||
HAL_GPIO_WritePin(W5500_1_SCS_PORT, W5500_1_SCS_PIN, GPIO_PIN_SET); // 置W5500的SCS为高电平
|
||||
return i; // 返回读取到的寄存器数据
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* 函数名 : Read_SOCK_Data_Buffer
|
||||
* 描述 : 从W5500接收数据缓冲区中读取数据
|
||||
* 输入 : s:端口号,*dat_ptr:数据保存缓冲区指针
|
||||
* 输出 : 无
|
||||
* 返回值 : 读取到的数据长度,rx_size个字节
|
||||
* 说明 : 无
|
||||
*******************************************************************************/
|
||||
static 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_1_SCS_PORT, W5500_1_SCS_PIN, GPIO_PIN_RESET); // 置W5500的SCS为低电平
|
||||
|
||||
SPI2_Send_Short(offset); // 写16位地址
|
||||
SPI2_Send_Byte(VDM | RWB_READ | (s * 0x20 + 0x18)); // 写控制字节,N个字节数据长度,读数据,选择端口s的寄存器
|
||||
j = hspi2.Instance->DR;
|
||||
// j=SPI_I2S_ReceiveData(SPI2);
|
||||
|
||||
if ((offset + rx_size) < S_RX_SIZE) // 如果最大地址未超过W5500接收缓冲区寄存器的最大地址
|
||||
{
|
||||
for (i = 0; i < rx_size; i++) // 循环读取rx_size个字节数据
|
||||
{
|
||||
SPI2_Send_Byte(0x00); // 发送一个哑数据
|
||||
j = hspi2.Instance->DR;
|
||||
// j=SPI_I2S_ReceiveData(SPI2);//读取1个字节数据
|
||||
*dat_ptr = j; // 将读取到的数据保存到数据保存缓冲区
|
||||
dat_ptr++; // 数据保存缓冲区指针地址自增1
|
||||
}
|
||||
}
|
||||
else // 如果最大地址超过W5500接收缓冲区寄存器的最大地址
|
||||
{
|
||||
offset = S_RX_SIZE - offset;
|
||||
for (i = 0; i < offset; i++) // 循环读取出前offset个字节数据
|
||||
{
|
||||
SPI2_Send_Byte(0x00); // 发送一个哑数据
|
||||
j = hspi2.Instance->DR;
|
||||
// j=SPI_I2S_ReceiveData(SPI2);//读取1个字节数据
|
||||
*dat_ptr = j; // 将读取到的数据保存到数据保存缓冲区
|
||||
dat_ptr++; // 数据保存缓冲区指针地址自增1
|
||||
}
|
||||
HAL_GPIO_WritePin(W5500_1_SCS_PORT, W5500_1_SCS_PIN, GPIO_PIN_SET); // 置W5500的SCS为高电平
|
||||
|
||||
HAL_GPIO_WritePin(W5500_1_SCS_PORT, W5500_1_SCS_PIN, GPIO_PIN_RESET); // 置W5500的SCS为低电平
|
||||
|
||||
SPI2_Send_Short(0x00); // 写16位地址
|
||||
SPI2_Send_Byte(VDM | RWB_READ | (s * 0x20 + 0x18)); // 写控制字节,N个字节数据长度,读数据,选择端口s的寄存器
|
||||
j = hspi2.Instance->DR;
|
||||
// j=SPI_I2S_ReceiveData(SPI2);
|
||||
|
||||
for (; i < rx_size; i++) // 循环读取后rx_size-offset个字节数据
|
||||
{
|
||||
SPI2_Send_Byte(0x00); // 发送一个哑数据
|
||||
j = hspi2.Instance->DR;
|
||||
// j=SPI_I2S_ReceiveData(SPI2);//读取1个字节数据
|
||||
*dat_ptr = j; // 将读取到的数据保存到数据保存缓冲区
|
||||
dat_ptr++; // 数据保存缓冲区指针地址自增1
|
||||
}
|
||||
}
|
||||
HAL_GPIO_WritePin(W5500_1_SCS_PORT, W5500_1_SCS_PIN, 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_1_Class, u8 *dat_ptr, u16 size)
|
||||
{
|
||||
u16 offset, offset1;
|
||||
u16 i;
|
||||
// 如果是UDP模式,可以在此设置目的主机的IP和端口号
|
||||
if ((Read_W5500_SOCK_1Byte(pW5500_1_Class->SocketPort, Sn_MR) & 0x0f) != SOCK_UDP) // 如果Socket打开失败
|
||||
{
|
||||
Write_W5500_SOCK_4Byte(pW5500_1_Class->SocketPort, Sn_DIPR, pW5500_1_Class->ConfigData.UDP_DIPR); // 设置目的主机IP
|
||||
Write_W5500_SOCK_2Byte(pW5500_1_Class->SocketPort, Sn_DPORTR, pW5500_1_Class->ConfigData.UDP_DPORT[0]<<8 | pW5500_1_Class->ConfigData.UDP_DPORT[1]); // 设置目的主机端口号
|
||||
}
|
||||
|
||||
offset = Read_W5500_SOCK_2Byte(pW5500_1_Class->SocketPort, Sn_TX_WR);
|
||||
offset1 = offset;
|
||||
offset &= (S_TX_SIZE - 1); // 计算实际的物理地址
|
||||
|
||||
HAL_GPIO_WritePin(W5500_1_SCS_PORT, W5500_1_SCS_PIN, GPIO_PIN_RESET); // 置W5500的SCS为低电平
|
||||
|
||||
SPI2_Send_Short(offset); // 写16位地址
|
||||
SPI2_Send_Byte(VDM | RWB_WRITE | (pW5500_1_Class->SocketPort * 0x20 + 0x10)); // 写控制字节,N个字节数据长度,写数据,选择端口s的寄存器
|
||||
|
||||
if ((offset + size) < S_TX_SIZE) // 如果最大地址未超过W5500发送缓冲区寄存器的最大地址
|
||||
{
|
||||
for (i = 0; i < size; i++) // 循环写入size个字节数据
|
||||
{
|
||||
SPI2_Send_Byte(*dat_ptr++); // 写入一个字节的数据
|
||||
}
|
||||
}
|
||||
else // 如果最大地址超过W5500发送缓冲区寄存器的最大地址
|
||||
{
|
||||
offset = S_TX_SIZE - offset;
|
||||
for (i = 0; i < offset; i++) // 循环写入前offset个字节数据
|
||||
{
|
||||
SPI2_Send_Byte(*dat_ptr++); // 写入一个字节的数据
|
||||
}
|
||||
HAL_GPIO_WritePin(W5500_1_SCS_PORT, W5500_1_SCS_PIN, GPIO_PIN_SET); // 置W5500的SCS为高电平
|
||||
|
||||
HAL_GPIO_WritePin(W5500_1_SCS_PORT, W5500_1_SCS_PIN, GPIO_PIN_RESET); // 置W5500的SCS为低电平
|
||||
|
||||
SPI2_Send_Short(0x00); // 写16位地址
|
||||
SPI2_Send_Byte(VDM | RWB_WRITE | (pW5500_1_Class->SocketPort * 0x20 + 0x10)); // 写控制字节,N个字节数据长度,写数据,选择端口s的寄存器
|
||||
|
||||
for (; i < size; i++) // 循环写入size-offset个字节数据
|
||||
{
|
||||
SPI2_Send_Byte(*dat_ptr++); // 写入一个字节的数据
|
||||
}
|
||||
}
|
||||
HAL_GPIO_WritePin(W5500_1_SCS_PORT, W5500_1_SCS_PIN, GPIO_PIN_SET); // 置W5500的SCS为高电平
|
||||
|
||||
offset1 += size; // 更新实际物理地址,即下次写待发送数据到发送数据缓冲区的起始地址
|
||||
Write_W5500_SOCK_2Byte(pW5500_1_Class->SocketPort, Sn_TX_WR, offset1);
|
||||
Write_W5500_SOCK_1Byte(pW5500_1_Class->SocketPort, Sn_CR, SEND); // 发送启动发送命令
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* 函数名 : W5500_Hardware_Reset
|
||||
* 描述 : 硬件复位W5500
|
||||
* 输入 : 无
|
||||
* 输出 : 无
|
||||
* 返回值 : 无
|
||||
* 说明 : W5500的复位引脚保持低电平至少500us以上,才能重围W5500
|
||||
*******************************************************************************/
|
||||
static void W5500_Hardware_Reset(void)
|
||||
{
|
||||
HAL_GPIO_WritePin(W5500_1_RST_PORT, W5500_1_RST_PIN, GPIO_PIN_RESET); // 复位引脚拉低
|
||||
HAL_Delay(50);
|
||||
HAL_GPIO_WritePin(W5500_1_RST_PORT, W5500_1_RST_PIN, GPIO_PIN_SET); // 复位引脚拉高
|
||||
HAL_Delay(100);
|
||||
|
||||
// while((Read_W5500_1Byte(PHYCFGR)&LINK)==0);//等待以太网连接完成
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* 函数名 : W5500_Init
|
||||
* 描述 : 初始化W5500寄存器函数
|
||||
* 输入 : 无
|
||||
* 输出 : 无
|
||||
* 返回值 : 无
|
||||
* 说明 : 在使用W5500之前,先对W5500初始化
|
||||
*******************************************************************************/
|
||||
static void W5500_Init(void)
|
||||
{
|
||||
#define STM32F1_UID_BASE 0x1FFFF7E8
|
||||
u16 i = 0;
|
||||
u32 uid[3] = {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_1->Gateway_IP, 4);
|
||||
|
||||
// 设置子网掩码(MASK)值,SUB_MASK为4字节u8数组,自己定义
|
||||
// 子网掩码用于子网运算
|
||||
Write_W5500_nByte(SUBR, pW5500_1->Sub_Mask, 4);
|
||||
|
||||
// 设置物理地址,PHY_ADDR为6字节u8数组,自己定义,用于唯一标识网络设备的物理地址值
|
||||
// 该地址值需要到IEEE申请,按照OUI的规定,前3个字节为厂商代码,后三个字节为产品序号
|
||||
// 如果自己定义物理地址,注意第一个字节必须为偶数
|
||||
// 设置物理地址,PHY_ADDR为6字节u8数组,自己定义,用于唯一标识网络设备的物理地址值
|
||||
// 该地址值需要到IEEE申请,按照OUI的规定,前3个字节为厂商代码,后三个字节为产品序号
|
||||
// 如果自己定义物理地址,注意第一个字节必须为偶数
|
||||
//使用单片机UID
|
||||
|
||||
uid[0] = *(u32*)(STM32F1_UID_BASE);
|
||||
uid[1] = *(u32*)(STM32F1_UID_BASE + 4 +1);
|
||||
uid[2] = *(u32*)(STM32F1_UID_BASE + 8 +1);
|
||||
|
||||
|
||||
pW5500_1->Phy_Addr[0] = uid[1] >> 8;
|
||||
pW5500_1->Phy_Addr[1] = uid[1];
|
||||
pW5500_1->Phy_Addr[2] = uid[2] >> 24;
|
||||
pW5500_1->Phy_Addr[3] = uid[2] >> 16;
|
||||
pW5500_1->Phy_Addr[4] = uid[2] >> 8;
|
||||
pW5500_1->Phy_Addr[5] = uid[2];
|
||||
|
||||
// 设置本地管理位,并将单播位清零
|
||||
pW5500_1->Phy_Addr[0] = (pW5500_1->Phy_Addr[0] & 0xFE) | 0x02;
|
||||
Write_W5500_nByte(SHAR, pW5500_1->Phy_Addr, 6);
|
||||
|
||||
// 设置本机的IP地址,IP_ADDR为4字节u8数组,自己定义
|
||||
// 注意,网关IP必须与本机IP属于同一个子网,否则本机将无法找到网关
|
||||
Write_W5500_nByte(SIPR, pW5500_1->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)
|
||||
* 说明 : 无
|
||||
*******************************************************************************/
|
||||
static u8 Detect_Gateway(void)
|
||||
{
|
||||
u8 ip_adde[4];
|
||||
ip_adde[0] = pW5500_1->IP_Addr[0] + 1;
|
||||
ip_adde[1] = pW5500_1->IP_Addr[1] + 1;
|
||||
ip_adde[2] = pW5500_1->IP_Addr[2] + 1;
|
||||
ip_adde[3] = pW5500_1->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_1_Class)
|
||||
{
|
||||
Write_W5500_SOCK_2Byte(pW5500_1_Class->SocketPort, Sn_MSSR, 1460); // 最大分片字节数=1460(0x5b4)
|
||||
Write_W5500_SOCK_2Byte(pW5500_1_Class->SocketPort, Sn_PORT, pW5500_1_Class->ConfigData.Port[0]<<8 | pW5500_1_Class->ConfigData.Port[1]);
|
||||
// 设置端口0目的(远程)端口号
|
||||
Write_W5500_SOCK_2Byte(pW5500_1_Class->SocketPort, Sn_DPORTR, pW5500_1_Class->ConfigData.DPort[0]<<8 | pW5500_1_Class->ConfigData.DPort[1]);
|
||||
// 设置端口0目的(远程)IP地址
|
||||
Write_W5500_SOCK_4Byte(pW5500_1_Class->SocketPort, Sn_DIPR, pW5500_1_Class->ConfigData.DIP);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* 函数名 : Socket_Connect
|
||||
* 描述 : 设置指定Socket(0~7)为客户端与远程服务器连接
|
||||
* 输入 : s:待设定的端口
|
||||
* 输出 : 无
|
||||
* 返回值 : 成功返回TRUE(0xFF),失败返回FALSE(0x00)
|
||||
* 说明 : 当本机Socket工作在客户端模式时,引用该程序,与远程服务器建立连接
|
||||
* 如果启动连接后出现超时中断,则与服务器连接失败,需要重新调用该程序连接
|
||||
* 该程序每调用一次,就与服务器产生一次连接
|
||||
*******************************************************************************/
|
||||
static 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设置为服务器模式
|
||||
*******************************************************************************/
|
||||
static 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模式
|
||||
*******************************************************************************/
|
||||
static 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_1->W5500_Class[i].SocketPort, Sn_IR); // 读取Socket0中断标志寄存器
|
||||
Write_W5500_SOCK_1Byte(pW5500_1->W5500_Class[i].SocketPort, Sn_IR, Socket_Flag);
|
||||
if (Socket_Flag & IR_CON) // 在TCP模式下,Socket0成功连接
|
||||
{
|
||||
pW5500_1->W5500_Class[i].Run_State |= BSP_W5500_PORT_RUN_STATE_CONN; // 网络连接状态0x02,端口完成连接,可以正常传输数据
|
||||
}
|
||||
if (Socket_Flag & IR_DISCON) // 在TCP模式下Socket断开连接处理
|
||||
{
|
||||
Write_W5500_SOCK_1Byte(pW5500_1->W5500_Class[i].SocketPort, Sn_CR, CLOSE); // 关闭端口,等待重新打开连接
|
||||
bsp_W5500_Socket_Init(&pW5500_1->W5500_Class[i]); // 指定Socket(0~7)初始化,初始化端口0
|
||||
pW5500_1->W5500_Class[i].Run_State = 0; // 网络连接状态0x00,端口连接失败
|
||||
}
|
||||
if (Socket_Flag & IR_SEND_OK) // Socket0数据发送完成,可以再次启动S_tx_process()函数发送数据
|
||||
{
|
||||
pW5500_1->W5500_Class[i].TR_Data_State |= BSP_W5500_PORT_DATA_TRANSMITOK; // 端口发送一个数据包完成
|
||||
}
|
||||
if (Socket_Flag & IR_RECV) // Socket接收到数据,可以启动S_rx_process()函数
|
||||
{
|
||||
pW5500_1->W5500_Class[i].TR_Data_State |= BSP_W5500_PORT_DATA_RECEIVE; // 端口接收到一个数据包
|
||||
}
|
||||
if (Socket_Flag & IR_TIMEOUT) {
|
||||
// 1. 清除超时中断标志位 (你的代码已有)
|
||||
Write_W5500_SOCK_1Byte(pW5500_1->W5500_Class[i].SocketPort, Sn_IR, Socket_Flag);
|
||||
|
||||
// 2. 强制关闭Socket,确保其状态机复位
|
||||
Write_W5500_SOCK_1Byte(pW5500_1->W5500_Class[i].SocketPort, Sn_CR, CLOSE);
|
||||
|
||||
// 3. (强烈推荐) 增加一小段延时,等待硬件完成关闭操作
|
||||
HAL_Delay(10);
|
||||
|
||||
// 4. 关键修复:重新打开Socket并进入监听模式
|
||||
// bsp_W5500_Socket_Init 函数用于配置Socket参数
|
||||
bsp_W5500_Socket_Init(&pW5500_1->W5500_Class[i]);
|
||||
// bsp_W5500_Socket_Set 函数会根据配置的模式(TCP Server)调用 Socket_Listen
|
||||
bsp_W5500_Socket_Set(&pW5500_1->W5500_Class[i]);
|
||||
|
||||
// 5. 清理相关的状态标志位
|
||||
pW5500_1->W5500_Class[i].Run_State = 0;
|
||||
pW5500_1->W5500_Class[i].TR_Data_State = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (Read_W5500_1Byte(SIR) != 0)
|
||||
goto IntDispose;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置指定Socket的Keep-Alive间隔
|
||||
* @param s: Socket端口号 (0~7)
|
||||
* @param interval_5s: 间隔时间,单位5秒,例如2表示10秒。0表示禁用。
|
||||
*/
|
||||
static void w5500_set_keepalive(SOCKET s, uint8_t interval_5s)
|
||||
{
|
||||
Write_W5500_SOCK_1Byte(s, Sn_KPALVTR, interval_5s);
|
||||
}
|
||||
|
||||
static void bsp_W5500_Socket_Set(bsp_W5500_Class_t *pW5500_1_Class)
|
||||
{
|
||||
if (0 == pW5500_1_Class->Run_State)
|
||||
{
|
||||
switch(pW5500_1_Class->Run_Mode)
|
||||
{
|
||||
/*TCP服务器模式*/
|
||||
case BSP_W5500_PORT_RUN_MODE_TCP_SERVER:
|
||||
{
|
||||
if (Socket_Listen(pW5500_1_Class->SocketPort) == TRUE)
|
||||
{
|
||||
pW5500_1_Class->Run_State = BSP_W5500_PORT_RUN_STATE_INIT;
|
||||
w5500_set_keepalive(pW5500_1_Class->SocketPort, 2);
|
||||
}
|
||||
else
|
||||
pW5500_1_Class->Run_State = 0;
|
||||
}break;
|
||||
/*TCP客户端模式*/
|
||||
case BSP_W5500_PORT_RUN_MODE_TCP_CLIENT:
|
||||
{
|
||||
if(Socket_Connect(pW5500_1_Class->SocketPort)==TRUE)
|
||||
pW5500_1_Class->Run_State = BSP_W5500_PORT_RUN_STATE_INIT;
|
||||
else
|
||||
pW5500_1_Class->Run_State = 0;
|
||||
}break;
|
||||
/*UDP模式*/
|
||||
case BSP_W5500_PORT_RUN_MODE_UDP:
|
||||
{
|
||||
if(Socket_UDP(pW5500_1_Class->SocketPort)==TRUE)
|
||||
pW5500_1_Class->Run_State = BSP_W5500_PORT_RUN_STATE_INIT | BSP_W5500_PORT_RUN_STATE_CONN;
|
||||
else
|
||||
pW5500_1_Class->Run_State = 0;
|
||||
}break;
|
||||
default:break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void bsp_W5500_Init()
|
||||
{
|
||||
u8 i;
|
||||
Wdg.Feed();
|
||||
W5500_Hardware_Reset(); /*硬件复位W5500*/
|
||||
W5500_Init(); /*初始化W5500寄存器函数*/
|
||||
Detect_Gateway(); /*检查网关服务器*/
|
||||
|
||||
|
||||
for(i=0;i<BSP_W5500_PORT_NUM;i++)
|
||||
{
|
||||
bsp_W5500_Socket_Init(&pW5500_1->W5500_Class[i]);
|
||||
pW5500_1->W5500_Class[i].Run_State = 0; /*复位状态*/
|
||||
//bsp_W5500_Socket_Set(&pW5500_1->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_1->W5500_Class[i]); /*W5500端口初始化配置*/
|
||||
}
|
||||
bsp_W5500_Interrupt_Process(); // W5500中断处理程序框架
|
||||
|
||||
for(i=0;i<BSP_W5500_PORT_NUM;i++)
|
||||
{
|
||||
if ((pW5500_1->W5500_Class[i].TR_Data_State & BSP_W5500_PORT_DATA_RECEIVE) == BSP_W5500_PORT_DATA_RECEIVE) // 如果Socket0接收到数据
|
||||
{
|
||||
pW5500_1->W5500_Class[i].TR_Data_State &= ~BSP_W5500_PORT_DATA_RECEIVE;
|
||||
u16 Len = Read_SOCK_Data_Buffer(pW5500_1->W5500_Class[i].SocketPort, pW5500_1->W5500_Class[i].Rx_Buffer);
|
||||
if(pW5500_1->W5500_Class[i].Rx_DataAnalysis != NULL)
|
||||
{
|
||||
pW5500_1->W5500_Class[i].Rx_DataAnalysis(&pW5500_1->W5500_Class[i],pW5500_1->W5500_Class[i].Rx_Buffer,Len);/*数据解析*/
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取 W5500 物理链路状态
|
||||
* @return 1: 链路连接, 0: 链路断开
|
||||
*/
|
||||
static u8 w5500_get_link_status(void)
|
||||
{
|
||||
u8 phycfgr = Read_W5500_1Byte(PHYCFGR); // 读取 PHYCFGR 寄存器
|
||||
return (phycfgr & LINK) ? 1 : 0; // 返回 LINK 位
|
||||
}
|
||||
|
||||
|
||||
static void network_monitor_task(void)
|
||||
{
|
||||
u8 current_link = w5500_get_link_status();
|
||||
|
||||
if (last_link_status == 0 && current_link == 1) {
|
||||
/*链路从断开变为连接,执行恢复操作*/
|
||||
W5500_1.Init();
|
||||
}
|
||||
|
||||
last_link_status = current_link;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
#ifndef __BSP_W5500_1_H
|
||||
#define __BSP_W5500_1_H
|
||||
|
||||
#include "bsp_W5500.h" // 复用原有寄存器定义和结构体
|
||||
|
||||
/* 第二个网口的引脚定义 */
|
||||
#define W5500_1_SCS_PORT GPIOB
|
||||
#define W5500_1_SCS_PIN GPIO_PIN_12
|
||||
|
||||
#define W5500_1_RST_PORT GPIOA
|
||||
#define W5500_1_RST_PIN GPIO_PIN_11
|
||||
|
||||
#define W5500_1_INT_PORT GPIOA
|
||||
#define W5500_1_INT_PIN GPIO_PIN_12
|
||||
|
||||
|
||||
/* 外部全局设备实例 */
|
||||
extern bsp_W5500_t W5500_1;
|
||||
|
||||
#endif
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -0,0 +1,94 @@
|
||||
#include "bsp_print.h"
|
||||
|
||||
#include "proto_modbus_tcp_master.h"
|
||||
|
||||
#include "bsp_Flash.h"
|
||||
|
||||
#include "stdio.h"
|
||||
|
||||
static u32 last_tick = 0; // 记录上次打印的 tick
|
||||
|
||||
/*重定义fputc函数*/
|
||||
int fputc(int ch, FILE *f)
|
||||
{
|
||||
u8 Data = ch;
|
||||
COM_Uart3.Send(&COM_Uart3,&Data,1);
|
||||
}
|
||||
|
||||
void Debug_UartSend(u8 *pData,u16 Len)
|
||||
{
|
||||
//COM_Uart1.Send(&COM_Uart1,pData,Len);
|
||||
}
|
||||
|
||||
void UartSend(u8 ch)
|
||||
{
|
||||
COM_Uart3.Send(&COM_Uart3,&ch,1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 每秒打印一次所有 Modbus TCP 数据(通过串口1)
|
||||
* @note 该函数需要被主循环(或定时任务)周期性调用。
|
||||
* 内部使用静态变量记录上次打印时刻,利用 os_timer 判断是否达到1秒。
|
||||
* 打印内容包括:状态寄存器(8个)、浮点值(26个)、整数值(4个)。
|
||||
*/
|
||||
void proto_modbus_print_1s(void)
|
||||
{
|
||||
u8 cnt = 0;
|
||||
// 检查是否已过 1000ms
|
||||
if (TIME_TRUE == OsTimer_CheckTimeOut(last_tick, osTime_MSecTick, 5000) && Usr_Flash.test == 2)
|
||||
{
|
||||
last_tick = osTime_MSecTick; // 更新时间戳
|
||||
|
||||
printf(
|
||||
"\r\n========== Modbus TCP Data ==========\r\n"
|
||||
"40000~40007: 0x%04X(%u), 0x%04X(%u), 0x%04X(%u), 0x%04X(%u), "
|
||||
"0x%04X(%u), 0x%04X(%u), 0x%04X(%u), 0x%04X(%u)\r\n"
|
||||
"40050~40100: %.3f, %.3f, %.3f, %.3f, %.3f, %.3f, %.3f, %.3f, "
|
||||
"%.3f, %.3f, %.3f, %.3f, %.3f, %.3f, %.3f, %.3f, "
|
||||
"%.3f, %.3f, %.3f, %.3f, %.3f, %.3f, %.3f, %.3f, "
|
||||
"%.3f, %.3f\r\n"
|
||||
"40250~40253: %u, %u, %u,\r\n"
|
||||
"========== End of Dump ==========\r\n",
|
||||
// 8个状态寄存器(每个打印两次:十六进制和十进制)
|
||||
modbus_tcp.data.reg_status[0], modbus_tcp.data.reg_status[0],
|
||||
modbus_tcp.data.reg_status[1], modbus_tcp.data.reg_status[1],
|
||||
modbus_tcp.data.reg_status[2], modbus_tcp.data.reg_status[2],
|
||||
modbus_tcp.data.reg_status[3], modbus_tcp.data.reg_status[3],
|
||||
modbus_tcp.data.reg_status[4], modbus_tcp.data.reg_status[4],
|
||||
modbus_tcp.data.reg_status[5], modbus_tcp.data.reg_status[5],
|
||||
modbus_tcp.data.reg_status[6], modbus_tcp.data.reg_status[6],
|
||||
modbus_tcp.data.reg_status[7], modbus_tcp.data.reg_status[7],
|
||||
// 26个浮点值
|
||||
modbus_tcp.data.float_values[0],
|
||||
modbus_tcp.data.float_values[1],
|
||||
modbus_tcp.data.float_values[2],
|
||||
modbus_tcp.data.float_values[3],
|
||||
modbus_tcp.data.float_values[4],
|
||||
modbus_tcp.data.float_values[5],
|
||||
modbus_tcp.data.float_values[6],
|
||||
modbus_tcp.data.float_values[7],
|
||||
modbus_tcp.data.float_values[8],
|
||||
modbus_tcp.data.float_values[9],
|
||||
modbus_tcp.data.float_values[10],
|
||||
modbus_tcp.data.float_values[11],
|
||||
modbus_tcp.data.float_values[12],
|
||||
modbus_tcp.data.float_values[13],
|
||||
modbus_tcp.data.float_values[14],
|
||||
modbus_tcp.data.float_values[15],
|
||||
modbus_tcp.data.float_values[16],
|
||||
modbus_tcp.data.float_values[17],
|
||||
modbus_tcp.data.float_values[18],
|
||||
modbus_tcp.data.float_values[19],
|
||||
modbus_tcp.data.float_values[20],
|
||||
modbus_tcp.data.float_values[21],
|
||||
modbus_tcp.data.float_values[22],
|
||||
modbus_tcp.data.float_values[23],
|
||||
modbus_tcp.data.float_values[24],
|
||||
modbus_tcp.data.float_values[25],
|
||||
// 3个整数值
|
||||
modbus_tcp.data.int_values[0],
|
||||
modbus_tcp.data.int_values[1],
|
||||
modbus_tcp.data.int_values[2]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
#ifndef _BSP_PRINT_H_
|
||||
#define _BSP_PRINT_H_
|
||||
|
||||
#include "main.h"
|
||||
|
||||
void Debug_UartSend(u8 *pData,u16 Len);
|
||||
void proto_modbus_print_1s(void);
|
||||
|
||||
#endif
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
#ifndef _SYS_H_
|
||||
#define _SYS_H_
|
||||
|
||||
#include "stm32f1xx.h"
|
||||
|
||||
//定义一些常用的数据类型短关键字
|
||||
typedef int64_t s64;
|
||||
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 uint64_t u64;
|
||||
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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user