【六足机器人】01功能开发
包含:WIFI模块、GPS模块、语言模块、调试信息接口。
一、硬件连接
huart4( PA0、 PA1 )与GPS模块连接。
huart3(PB10、PB11)与ESP8266模块连接。
huart2( PA2、 PA3 )与语音模块连接。
huart1(PB14、PB15)与PC端连接,用于打印调试信息。
二、串口配置代码
2.1 开启中断:
开启串口的接收中断 or 空闲中断。
/* 该函数会开启接收中断:标志位UART_IT_RXNE,并且设置接收缓冲以及接收缓冲接收最大数据量 */HAL_UART_Receive_IT(&huart1, (uint8_t *)g_rx_buffer, 1);// __HAL_UART_ENABLE_IT(&huart3, UART_IT_IDLE);// HAL_UART_Receive_DMA(&huart3,(uint8_t*)ATCmdRxBuffer,ATCmdRxBuffe_MAX_SIZE); //重新启动DMA接收__HAL_UART_ENABLE_IT(&huart2, UART_IT_IDLE); //使能IDLE中断 HAL_UART_Receive_DMA(&huart2, voiceBuf, voiceBuf_MAX_SIZE);
//HAL_UART_Receive_DMA(&huart3, (uint8_t *)g_rx_buffer, 1);__HAL_UART_ENABLE_IT(&huart3, UART_IT_RXNE); /* 使能UART接收中断 */__HAL_UART_ENABLE_IT(&huart3, UART_IT_IDLE); /* 使能UART总线空闲中断 */
2.2 中断函数:
/* USER CODE BEGIN 1 */void HAL_UART_MyIdleCpltCallback(UART_HandleTypeDef *huart)
{if (huart->Instance == USART2){Voice_Length = voiceBuf_MAX_SIZE - __HAL_DMA_GET_COUNTER(&hdma_usart2_rx);flag_voice = 1; // 设置接收完成标志}
}void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) // 串口接收完成中断回调函数
{if (huart->Instance == USART1) /* 如果是串口1 */{if ((myHexapodRx.recv_end_flag & 0x8000) == 0) /* 接收未完成 1000 0000 0000 0000 */ {if (myHexapodRx.recv_end_flag & 0x4000) /* 接收到了0x0D /r 0100 0000 0000 0000 */{if (g_rx_buffer[0] != 0x0a) /* \n 0x0A*/{myHexapodRx.recv_end_flag = 0; /* 接收错误,重新开始 */}else{myHexapodRx.recv_end_flag |= 0x8000; /* 接收完成了 */}}else /* 还没收到0X0D */{if (g_rx_buffer[0] == 0x0d){myHexapodRx.recv_end_flag |= 0x4000;} else{ //0011 1111 1111 1111myHexapodRx.HexapodRxBuf[myHexapodRx.recv_end_flag & 0X3FFF] = g_rx_buffer[0];myHexapodRx.recv_end_flag++;if (myHexapodRx.recv_end_flag > (HexapodRxBuf_MAX_SIZE - 1)){myHexapodRx.recv_end_flag = 0; /* 接收数据错误,重新开始接收 */}}}}HAL_UART_Receive_IT(&huart1, (uint8_t *)g_rx_buffer, 1);}if (huart->Instance == USART2){HAL_UART_Receive_DMA(&huart2, (uint8_t *)voiceBuf, voiceBuf_MAX_SIZE);}
三、功能模块
3.1 ESP8266模块
3.1.1 atk_ESP8266D
atk_mw8266d_usart.c
#include "atk_mw8266d_usart.h"
#include "usart.h"
#include <stdarg.h>
#include <stdio.h>
#include <string.h>g_uart_rx_frame myATCmdRx = {0};static uint8_t g_uart_tx_buf[ATK_MW8266D_UART_TX_BUF_SIZE]; /* ATK-MW8266D UART发送缓冲 *//*** @brief ATK-MW8266D UART printf* @param fmt: 待发送的数据* @retval 无*/
void atk_mw8266d_uart_printf(char *fmt, ...)
{va_list ap;uint16_t len;va_start(ap, fmt);vsprintf((char *)g_uart_tx_buf, fmt, ap);va_end(ap);len = strlen((const char *)g_uart_tx_buf);HAL_UART_Transmit(&g_uart_handle, g_uart_tx_buf, len, HAL_MAX_DELAY);//HAL_UART_Transmit_IT(&g_uart_handle, g_uart_tx_buf, sizeof(g_uart_tx_buf));
}/*** @brief ATK-MW8266D UART重新开始接收数据* @param 无* @retval 无*/
void atk_mw8266d_uart_rx_restart(void)
{myATCmdRx.sta.len = 0;myATCmdRx.sta.finsh = 0;
}/*** @brief 获取ATK-MW8266D UART接收到的一帧数据* @param 无* @retval NULL: 未接收到一帧数据* 其他: 接收到的一帧数据*/
uint8_t *atk_mw8266d_uart_rx_get_frame(void)
{if (myATCmdRx.sta.finsh == 1){myATCmdRx.buf[myATCmdRx.sta.len] = '\0';//printf("接收到的数据: %s\r\n", myATCmdRx.buf);return myATCmdRx.buf; }else{return NULL;}
}/*** @brief 获取ATK-MW8266D UART接收到的一帧数据的长度* @param 无* @retval 0 : 未接收到一帧数据* 其他: 接收到的一帧数据的长度*/
uint16_t atk_mw8266d_uart_rx_get_frame_len(void)
{if (myATCmdRx.sta.finsh == 1){return myATCmdRx.sta.len;}else{return 0;}
}/*** @brief ATK-MW8266D UART初始化* @param baudrate: UART通讯波特率* @retval 无*/
void atk_mw8266d_uart_init(uint32_t baudrate)
{g_uart_handle.Instance = ATK_MW8266D_UART_INTERFACE; /* ATK-MW8266D UART */g_uart_handle.Init.BaudRate = baudrate; /* 波特率 */g_uart_handle.Init.WordLength = UART_WORDLENGTH_8B; /* 数据位 */g_uart_handle.Init.StopBits = UART_STOPBITS_1; /* 停止位 */g_uart_handle.Init.Parity = UART_PARITY_NONE; /* 校验位 */g_uart_handle.Init.Mode = UART_MODE_TX_RX; /* 收发模式 */g_uart_handle.Init.HwFlowCtl = UART_HWCONTROL_NONE; /* 无硬件流控 */g_uart_handle.Init.OverSampling = UART_OVERSAMPLING_16; /* 过采样 */HAL_UART_Init(&g_uart_handle); /* 使能ATK-MW8266D UART* HAL_UART_Init()会调用函数HAL_UART_MspInit()* 该函数定义在文件usart.c中*/
}/*** @brief ATK-MW8266D UART中断回调函数* @param 无* @retval 无*/
void ATK_MW8266D_UART_IRQHandler(void)
{uint8_t tmp;if (__HAL_UART_GET_FLAG(&g_uart_handle, UART_FLAG_ORE) != RESET) /* UART接收过载错误中断 */{__HAL_UART_CLEAR_OREFLAG(&g_uart_handle); /* 清除接收过载错误中断标志 */(void)g_uart_handle.Instance->ISR; /* I先读SR寄存器,再读RDR寄存器 */(void)g_uart_handle.Instance->RDR;}if (__HAL_UART_GET_FLAG(&g_uart_handle, UART_FLAG_RXNE) != RESET) /* UART接收中断 */{HAL_UART_Receive(&g_uart_handle, &tmp, 1, 1000); /* UART接收数据 */if (myATCmdRx.sta.len < (ATK_MW8266D_UART_RX_BUF_SIZE - 1)) /* 判断UART接收缓冲是否溢出* 留出一位给结束符'\0'*/{myATCmdRx.buf[myATCmdRx.sta.len] = tmp; /* 将接收到的数据写入缓冲 */myATCmdRx.sta.len++; /* 更新接收到的数据长度 */}else /* UART接收缓冲溢出 */{myATCmdRx.sta.len = 0; /* 覆盖之前收到的数据 */myATCmdRx.buf[myATCmdRx.sta.len] = tmp; /* 将接收到的数据写入缓冲 */myATCmdRx.sta.len++; /* 更新接收到的数据长度 */}}if (__HAL_UART_GET_FLAG(&g_uart_handle, UART_FLAG_IDLE) != RESET) /* UART总线空闲中断 */{myATCmdRx.sta.finsh = 1; /* 标记帧接收完成 */__HAL_UART_CLEAR_IDLEFLAG(&g_uart_handle); /* 清除UART总线空闲中断 */}
}
atk_mw8266d_usart.h
#ifndef __ATK_MW8266D_UART_H
#define __ATK_MW8266D_UART_H#include "main.h"/* 引脚定义 */
#define ATK_MW8266D_UART_TX_GPIO_PORT GPIOB
#define ATK_MW8266D_UART_TX_GPIO_PIN GPIO_PIN_10
#define ATK_MW8266D_UART_TX_GPIO_AF GPIO_AF7_USART2
#define ATK_MW8266D_UART_TX_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOB_CLK_ENABLE(); }while(0) /* PA口时钟使能 */#define ATK_MW8266D_UART_RX_GPIO_PORT GPIOB
#define ATK_MW8266D_UART_RX_GPIO_PIN GPIO_PIN_11
#define ATK_MW8266D_UART_RX_GPIO_AF GPIO_AF7_USART2
#define ATK_MW8266D_UART_RX_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOB_CLK_ENABLE(); }while(0) /* PA口时钟使能 */#define ATK_MW8266D_UART_INTERFACE USART3
#define ATK_MW8266D_UART_IRQn USART3_IRQn
//#define ATK_MW8266D_UART_IRQHandler USART3_IRQHandler
#define ATK_MW8266D_UART_CLK_ENABLE() do{ __HAL_RCC_USART3_CLK_ENABLE(); }while(0) /* USART3 时钟使能 *//* UART收发缓冲大小 */
#define ATK_MW8266D_UART_RX_BUF_SIZE 128
#define ATK_MW8266D_UART_TX_BUF_SIZE 64
#define g_uart_handle huart3typedef struct
{uint8_t buf[ATK_MW8266D_UART_RX_BUF_SIZE]; /* 帧接收缓冲 */struct{uint16_t len : 15; /* 帧接收长度,sta[14:0] */uint16_t finsh : 1; /* 帧接收完成标志,sta[15] */} sta; /* 帧状态信息 */
} g_uart_rx_frame; /* ATK-MW8266D UART接收帧缓冲信息结构体 */extern g_uart_rx_frame myATCmdRx;/* 操作函数 */
void atk_mw8266d_uart_printf(char *fmt, ...); /* ATK-MW8266D UART printf */
void atk_mw8266d_uart_rx_restart(void); /* ATK-MW8266D UART重新开始接收数据 */
uint8_t *atk_mw8266d_uart_rx_get_frame(void); /* 获取ATK-MW8266D UART接收到的一帧数据 */
uint16_t atk_mw8266d_uart_rx_get_frame_len(void); /* 获取ATK-MW8266D UART接收到的一帧数据的长度 */
void atk_mw8266d_uart_init(uint32_t baudrate); /* ATK-MW8266D UART初始化 */
void ATK_MW8266D_UART_IRQHandler(void);
#endif
3.1.2 myTask_atk8266D
myTask_atk8266D.c
#include "myTask_ATK8266D.h"
#include "atk_mw8266d.h"
#include "usart.h"
#include "main.h"
#include "stdio.h"
#include "string.h"
#include "led.h"#define DEMO_WIFI_SSID "guilin88"
#define DEMO_WIFI_PWD "12345678"
#define DEMO_TCP_SERVER_IP "192.168.96.95"
#define DEMO_TCP_SERVER_PORT "6688"void myTask_ATK8266D(void)
{uint8_t ret;//char ip_buf[16];/* 初始化ATK-MW8266D */printf("开始连接AP.......\r\n");ret = atk_mw8266d_init(115200);if (ret != 0){printf("ATK-MW8266D init failed!\r\n");while (1){LED_R_Toggle;delay_ms(200);}}
// printf("正在恢复出厂设置...\r\n");
// while (atk_mw8266d_restore())
// {
// color_debug();
// }printf("正在进行AT测试...\r\n");while (atk_mw8266d_at_test()){color_debug();}
// printf("正在设置波特率...\r\n");
// ret = atk_mw8266d_send_at_cmd("AT+UART=115200,8,1,0,0", "OK", 500);
// while (ret != 0)
// {
// color_debug();
// }printf("正在设置Station模式...\r\n");while (atk_mw8266d_set_mode(1)){color_debug();}
// printf("正在进行软件复位...\r\n");
// while (atk_mw8266d_sw_reset())
// {
// color_debug();
// }
// printf("关闭回显功能...\r\n");
// while (atk_mw8266d_ate_config(0))
// {
// color_debug();
// }printf("正在连接WIFI...\r\n");while (atk_mw8266d_join_ap(DEMO_WIFI_SSID, DEMO_WIFI_PWD)){printf("Error to connect tcp server! 2秒后重新连接!\r\n");color_debug();}
// printf("获取IP地址中...\r\n");
// while (atk_mw8266d_get_ip(ip_buf))
// {
// color_debug();
// }// printf("IP: %s\r\n", ip_buf);/* 连接TCP服务器 */printf("正在连接TCP服务器...\r\n");while (atk_mw8266d_connect_tcp_server(DEMO_TCP_SERVER_IP, DEMO_TCP_SERVER_PORT)){printf("Error to connect tcp server! 2秒后重新连接!\r\n");color_debug();}/* 进入透传 */printf("进入透传...\r\n");while (atk_mw8266d_enter_unvarnished()){color_debug();}printf("成功进入透传\r\n");atk_mw8266d_uart_rx_restart(); // 重新开始接收数据
}
myTask_atk8266D.h
#ifndef _MYTASK_ATK8266D_H
#define _MYTASK_ATK8266D_Hvoid myTask_ATK8266D(void);#endif
3.2 GPS模块
3.2.1 ATGM336H
ATGM336H.c
#include "ATGM336H.h"
#include "main.h"
#include "usart.h"
#include "string.h"
#include "stdio.h"char rxdatabufer;
u16 point1 = 0;_SaveData Save_Data;
LatitudeAndLongitude_s g_LatAndLongData =
{.E_W = 0,.N_S = 0,.latitude = 0.0,.longitude = 0.0
};// 串口1中断服务程序
// 注意,读取USARTx->SR能避免莫名其妙的错误
char USART_RX_BUF[USART_REC_LEN]; // 接收缓冲,最大USART_REC_LEN个字节.
uint8_t uart_A_RX_Buff;// 接收状态
// bit15, 接收完成标志
// bit14, 接收到0x0d
// bit13~0, 接收到的有效字节数目
u16 USART_RX_STA=0; // 接收状态标记void atgm336h_init(void)
{clrStruct();HAL_UART_Receive_IT(&huart4, &uart_A_RX_Buff, 1);
}//GPS中断回调函数,需要放入串口接收中断中
void atgm336h_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{if(huart->Instance == UART4){
// printf("%c", uart_A_RX_Buff);if(uart_A_RX_Buff == '$'){point1 = 0;}USART_RX_BUF[point1++] = uart_A_RX_Buff;if(USART_RX_BUF[0] == '$' && USART_RX_BUF[4] == 'M' && USART_RX_BUF[5] == 'C') //确定是否收到"GPRMC/GNRMC"这一帧数据{if(uart_A_RX_Buff == '\n'){memset(Save_Data.GPS_Buffer, 0, GPS_Buffer_Length); //清空memcpy(Save_Data.GPS_Buffer, USART_RX_BUF, point1); //保存数据Save_Data.isGetData = true;point1 = 0;memset(USART_RX_BUF, 0, USART_REC_LEN); //清空}}if(point1 >= USART_REC_LEN){point1 = USART_REC_LEN;}HAL_UART_Receive_IT(&huart4, &uart_A_RX_Buff, 1);}
}u8 Hand(char *a) // 串口命令识别函数
{if(strstr(USART_RX_BUF, a)!=NULL)return 1;elsereturn 0;
}void CLR_Buf(void) // 串口缓存清理
{memset(USART_RX_BUF, 0, USART_REC_LEN); //清空point1 = 0;
}void clrStruct(void)
{Save_Data.isGetData = false;Save_Data.isParseData = false;Save_Data.isUsefull = false;memset(Save_Data.GPS_Buffer, 0, GPS_Buffer_Length); //清空memset(Save_Data.UTCTime, 0, UTCTime_Length);memset(Save_Data.latitude, 0, latitude_Length);memset(Save_Data.N_S, 0, N_S_Length);memset(Save_Data.longitude, 0, longitude_Length);memset(Save_Data.E_W, 0, E_W_Length);
}void errorLog(int num)
{while (1){printf("ERROR%d\r\n",num);}
}void parseGpsBuffer(void)
{char *subString;char *subStringNext;char i = 0;uint16_t Number=0, Integer=0, Decimal=0;if (Save_Data.isGetData){Save_Data.isGetData = false;printf("**************\r\n");printf("%s\r\n", Save_Data.GPS_Buffer);for (i = 0 ; i <= 6 ; i++){if (i == 0){if ((subString = strstr(Save_Data.GPS_Buffer, ",")) == NULL)errorLog(1); //解析错误}else{subString++;if ((subStringNext = strstr(subString, ",")) != NULL){char usefullBuffer[2];switch(i){case 1:memcpy(Save_Data.UTCTime, subString, subStringNext - subString);break; //获取UTC时间case 2:memcpy(usefullBuffer, subString, subStringNext - subString);break; //获取UTC时间case 3:memcpy(Save_Data.latitude, subString, subStringNext - subString);break; //获取纬度信息case 4:memcpy(Save_Data.N_S, subString, subStringNext - subString);break; //获取N/Scase 5:memcpy(Save_Data.longitude, subString, subStringNext - subString);break; //获取经度信息case 6:memcpy(Save_Data.E_W, subString, subStringNext - subString);break; //获取E/Wdefault:break;}subString = subStringNext;Save_Data.isParseData = true;if(usefullBuffer[0] == 'A')Save_Data.isUsefull = true;else if(usefullBuffer[0] == 'V')Save_Data.isUsefull = false;}else{errorLog(2); //解析错误}}}if (Save_Data.isParseData){if(Save_Data.isUsefull){// 获取 N/S 和 E/Wg_LatAndLongData.N_S = Save_Data.N_S[0];g_LatAndLongData.E_W = Save_Data.E_W[0];// 获取纬度for(uint8_t i=0; i<9; i++){if(i<2){Number *= 10;Number += Save_Data.latitude[i]-'0';}else if(i<4){Integer *= 10;Integer += Save_Data.latitude[i]-'0';}else if(i==4);else if(i<9){Decimal *= 10;Decimal += Save_Data.latitude[i]-'0';}}g_LatAndLongData.latitude = 1.0*Number + (1.0*Integer+1.0*Decimal/10000)/60;Number = 0;Integer = 0;Decimal = 0;// 获取经度for(uint8_t i=0; i<10; i++){if(i<3){Number *= 10;Number += Save_Data.longitude[i]-'0';}else if(i<5){Integer *= 10;Integer += Save_Data.longitude[i]-'0';}else if(i==5);else if(i<10){Decimal *= 10;Decimal += Save_Data.longitude[i]-'0';}}g_LatAndLongData.longitude = 1.0*Number + (1.0*Integer+1.0*Decimal/10000)/60;}}}
}void printGpsBuffer(void)
{if (Save_Data.isParseData){Save_Data.isParseData = false;printf("Save_Data.UTCTime = %s\r\n", Save_Data.UTCTime);if(Save_Data.isUsefull){Save_Data.isUsefull = false;printf("Save_Data.latitude = %s\r\n", Save_Data.latitude);printf("Save_Data.N_S = %s", Save_Data.N_S);printf("Save_Data.longitude = %s", Save_Data.longitude);printf("Save_Data.E_W = %s\r\n", Save_Data.E_W);printf("latitude: %c,%.4f\r\n", g_LatAndLongData.N_S, g_LatAndLongData.latitude);printf("longitude: %c,%.4f\r\n", g_LatAndLongData.E_W, g_LatAndLongData.longitude);}else{printf("GPS DATA is not usefull!\r\n");}}
}
ATGM336H.h
#ifndef __ATGM336H_H
#define __ATGM336H_H#include "usart.h"
#include "sys.h"
// #include "stdbool.h"#define USART_REC_LEN 200 // 定义最大接收字节数 200
#define EN_USART1_RX 1 // 使能(1)/禁止(0)串口1接收#define false 0
#define true 1// 定义数组长度
#define GPS_Buffer_Length 80
#define UTCTime_Length 11
#define latitude_Length 11
#define N_S_Length 2
#define longitude_Length 12
#define E_W_Length 2typedef struct SaveData
{char GPS_Buffer[GPS_Buffer_Length];char isGetData; // 是否获取到GPS数据char isParseData; // 是否解析完成char UTCTime[UTCTime_Length]; // UTC时间char latitude[latitude_Length]; // 纬度char N_S[N_S_Length]; // N/Schar longitude[longitude_Length]; // 经度char E_W[E_W_Length]; // E/Wchar isUsefull; // 定位信息是否有效
} _SaveData;// 经纬度数据
typedef struct _LatitudeAndLongitude_s
{float latitude; // 纬度float longitude; // 经度char N_S; // 北南char E_W; // 东西
} LatitudeAndLongitude_s;extern char rxdatabufer;
extern u16 point1;
extern _SaveData Save_Data;
extern LatitudeAndLongitude_s g_LatAndLongData;void atgm336h_UART_RxCpltCallback(UART_HandleTypeDef *huart);
void atgm336h_init(void); // 初始化
void clrStruct(void); // 清除结构体数据
void parseGpsBuffer(void); // 解包函数
void printGpsBuffer(void); // 打印函数#endif // __ATGM336H_H
3.2.2 myTask_GPS
myTask_GPS.c
#include "myTask_GPS.h"
#include "stdio.h"
#include "ATGM336H.h"void myTask_GPS(void){atgm336h_init();while (1){if (Save_Data.isParseData){Save_Data.isParseData = false;if(Save_Data.isUsefull){Save_Data.isUsefull = false;printf("latitude: %c,%.4f\r\n", g_LatAndLongData.N_S, g_LatAndLongData.latitude);printf("longitude: %c,%.4f\r\n", g_LatAndLongData.E_W, g_LatAndLongData.longitude);}else{printf("GPS DATA is not usefull!\r\n");}}HAL_Delay(30);}
}
3.3 语音模块
直接使用串口2接收指令信息。
3.4 串口重定义
支持printf函数,便于打印调试信息到PC端,适配STM32H7系列。其他系列需要查看不同的芯片手册。
/******************************************************************************************/
/* 加入以下代码, 支持printf函数, 而不需要选择use MicroLIB */#if 1
#if (__ARMCC_VERSION >= 6010050) /* 使用AC6编译器时 */
__asm(".global __use_no_semihosting\n\t"); /* 声明不使用半主机模式 */
__asm(".global __ARM_use_no_argv \n\t"); /* AC6下需要声明main函数为无参数格式,否则部分例程可能出现半主机模式 */#else
/* 使用AC5编译器时, 要在这里定义__FILE 和 不使用半主机模式 */
#pragma import(__use_no_semihosting)struct __FILE
{int handle;/* Whatever you require here. If the only file you are using is *//* standard output using printf() for debugging, no file handling *//* is required. */
};#endif/* 不使用半主机模式,至少需要重定义_ttywrch\_sys_exit\_sys_command_string函数,以同时兼容AC6和AC5模式 */
int _ttywrch(int ch)
{ch = ch;return ch;
}/* 定义_sys_exit()以避免使用半主机模式 */
void _sys_exit(int x)
{x = x;
}char *_sys_command_string(char *cmd, int len)
{return NULL;
}/* FILE 在 stdio.h里面定义. */
FILE __stdout;/* 重定义fputc函数, printf函数最终会通过调用fputc输出字符串到串口 */
int fputc(int ch, FILE *f)
{while ((USART1->ISR & 0X40) == 0); /* 等待上一个字符发送完成 */USART1->TDR = (uint8_t)ch; /* 将要发送的字符 ch 写入到DR寄存器 */return ch;
}
#endif
/***********************************************END*******************************************/
相关文章:

【六足机器人】01功能开发
包含:WIFI模块、GPS模块、语言模块、调试信息接口。 一、硬件连接 huart4( PA0、 PA1 )与GPS模块连接。 huart3(PB10、PB11)与ESP8266模块连接。 huart2( PA2、 PA3 )与语音模块连接。 hu…...

notepad++安装教程(超详细)
1.下载地址(可以私信博主) https://notepad-plus.en.softonic.com/download 2.解压安装...

创建简单的 PL/pgSQL 存储过程
文章目录 创建简单的 PL/pgSQL 存储过程CREATE OR REPLACE FUNCTIONadd_two_numbers(a integer, b integer)RETURNS integerAS$$ ... $$函数体LANGUAGE plpgsql 创建带有 IN 和 OUT 参数的存储过程创建修改数据的存储过程创建带有异常处理的复杂存储过程 在 PostgreSQL 中&…...

Java项目实战II基于微信小程序的无中介租房系统(开发文档+数据库+源码)
目录 一、前言 二、技术介绍 三、系统实现 四、核心代码 五、源码获取 全栈码农以及毕业设计实战开发,CSDN平台Java领域新星创作者,专注于大学生项目实战开发、讲解和毕业答疑辅导。 一、前言 随着城市化进程的加速,租房市场日益繁荣&a…...

Node.js实现WebSocket教程
Node.js实现WebSocket教程 1. WebSocket简介 WebSocket是一种在单个TCP连接上提供全双工通信的协议,允许服务器和客户端之间进行实时、双向通信。本教程将详细讲解如何在Node.js中实现WebSocket。 2. 技术选型 我们将使用ws库来实现WebSocket服务器,…...

Docker Compose实战一( 轻松部署 Nginx)
通过过前面的文章(Docker Compose基础语法)你已经掌握基本语法和常用指令认识到Docker Compose作为一款强大工具的重要性,它极大地简化了多容器Docker应用程序的部署与管理流程。本文将详细介绍如何使用 Docker Compose 部署 Nginx࿰…...

hive分区分桶、数据倾斜总结
一、hive的基本概念 hive是一个构建在hadoop上的数据仓库工具,可以将结构化的数据文件映射为一张数据库表并提供数据查询功能 二、hive的特点 (1)数据是存储在hdfs上 (2)底层是将sql转换为MapReduce任务进行计算 …...

unity打包到安卓帧率降低
这个问题遇到过很多次了我的做法就是直接设置Application.targetFrameRate60 参考...

【Python3】装饰器 自动更新缓存
自动更新缓存的需求场景 在某些应用中,我们可能需要定期从外部数据源(如 Redis 或者远程接口)拉取数据,并将其缓存在内存中。当有其他代码需要访问这些数据时,可以立刻从内存获取最新数据,而无需每次都进行…...

通过EPEL 仓库,在 CentOS 7 上安装 OpenResty
通过EPEL 仓库,在 CentOS 7 上安装 OpenResty 通过EPEL 仓库,在 CentOS 7 上安装 OpenResty步骤 1: 安装 EPEL 仓库步骤 2: 安装 OpenResty步骤 3: 启动 OpenResty步骤 4: 设置开机自启步骤 5: 验证安装说明 通过EPEL 仓库,在 CentOS 7 上安装…...

[RabbitMQ] RabbitMQ常见应用问题
🌸个人主页:https://blog.csdn.net/2301_80050796?spm1000.2115.3001.5343 🏵️热门专栏: 🧊 Java基本语法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12615970.html?spm1001.2014.3001.5482 🍕 Collection与…...

每日速记10道java面试题13-MySQL篇
其他资料 每日速记10道java面试题01-CSDN博客 每日速记10道java面试题02-CSDN博客 每日速记10道java面试题03-CSDN博客 每日速记10道java面试题04-CSDN博客 每日速记10道java面试题05-CSDN博客 每日速记10道java面试题06-CSDN博客 每日速记10道java面试题07-CSDN博客 每…...

乐鑫科技嵌入式面试题及参考答案(3万字长文)
嵌入式开发为什么用 C 语言,而不用 C++ 语言? 在嵌入式开发中,C 语言被广泛使用而 C++ 相对少用有以下一些原因。 首先,C 语言具有更高的效率。嵌入式系统通常资源受限,包括处理器速度、内存容量等。C 语言的代码生成效率高,能够生成紧凑的机器码,占用较少的内存空间和处…...

Leetcode 每日一题 56.合并区间
目录 问题描述 示例 示例 1 示例 2 问题分析 算法设计 步骤 1:排序 步骤 2:合并区间 步骤 3:返回结果 过题图片 代码实现 复杂度分析 题目链接 结语 问题描述 给定一个区间数组 intervals,其中每个区间由两个整数 s…...

【Vue】v-model、ref获取DOM
目录 v-moel v-model的原理 v-model用在组件标签上 方式 defineModel()简写 ref属性 获取原生DOM 获取组件实例 nextTick() v-moel v-model:双向数据绑定指令 数据变了,视图跟着变(数据驱动视图)视图变了,数…...

Python 类的设计(以植物大战僵尸为例)
关于类的设计——以植物大战僵尸为例 一、设计类需满足的三要素1. 类名2. 属性和方法 二、以植物大战僵尸的为例的类的设计1. 尝试分类2. 创建对象调用类的属性和方法*【代码二】*3. 僵尸的继承 三、代码实现 一、设计类需满足的三要素 1. 类名 类名:某类事物的名…...

python中权重剪枝,低秩分解,量化技术 代码
目录 python中权重剪枝,低秩分解,量化技术 代码 权重剪枝 低秩分解 scipy 量化技术 python中权重剪枝,低秩分解,量化技术 代码 权重剪枝 权重剪枝可以通过PyTorch的torch.nn.utils.prune模块实现。以下是一个简单的例子: import torch import torch.nn as nn impor…...

调用matlab用户自定义的function函数时,有多个输出变量只输出第一个变量
很多朋友在使用matlab时,会使用或自己编辑多个function函数,来满足自己对任务处理的要求,但是在调用function函数时,会出现这个问题:调用matlab用户自定义的function函数时,有多个输出变量只输出第一个变量…...

RabbitMQ七种工作模式之简单模式, 工作队列模式, 发布订阅模式, 路由模式, 通配符模式
文章目录 一. Simple(简单模式)公共代码:生产者:消费者: 二. Work Queue(工作队列模式)公共代码:生产者:消费者1, 消费者2(代码相同): 三. Publish/Subscribe(发布/订阅模式)公共代码:生产者:消费者: 四. Routing(路由模式)公共代码:消费者: 五. Topics(通配符模式)公共代码:生…...

Win10安装kafka并用C#调用
kafka安装 jdk、kafka版本如下,zookeeper使用kafka自带版本 安装包下载位置:https://download.csdn.net/download/henreash/90087368 (赚点csdn下载资源分) 安装jdk后,解压kafka压缩包,修改配置文件: kafka_2.13-3.9.0\config\…...

高级架构二 Git基础到高级
一 Git仓库的基本概念和流程 什么是版本库?版本库又名仓库,英文名repository,你可以简单的理解一个目录,这个目录里面的所有文件都可以被Git管理起来,每个文件的修改,删除,Git都能跟踪,以便任何…...

深入解析二叉树算法
引言 二叉树(Binary Tree)作为数据结构中的一种重要形式,在计算机科学的诸多领域中得到了广泛应用。从文件系统到表达式解析,再到搜索和排序,二叉树都扮演着关键角色。本文将从二叉树的基础概念出发,详细探讨其各种算法及其应用,并提供相关代码示例,旨在为读者建立扎实…...

如何解决maven项目使用Ctrl + /添加注释时的顶格问题
一、问题描述 相信后端开发的程序员一定很熟悉IDEA编译器和Maven脚手架,使用IDEA新建一个Maven工程,通过SpringBoot快速构建Spring项目。在Spring项目pom.xml文件中想添加注释,快捷键Ctrl /,但是总是顶格书写。 想保证缩进统一…...

总结的一些MySql面试题
目录 一:基础篇 二:索引原理和SQL优化 三:事务原理 四:缓存策略 一:基础篇 1:定义:按照数据结构来组织、存储和管理数据的仓库;是一个长期存储在计算机内的、有组织的、可共享 的…...

渤海证券基于互联网环境的漏洞主动防护方案探索与实践
来源:中国金融电脑 作者:渤海证券股份有限公司信息技术总部 刘洋 伴随互联网业务的蓬勃发展,证券行业成为黑客进行网络攻击的重要目标之一,网络攻击的形式也变得愈发多样且复杂。网络攻击如同悬于行业之上的达摩克利斯之剑&…...

用Go语言重写Linux系统命令 -- nc简化版
用Go语言重写Linux系统命令 – nc简化版 1. 引言 netcat,简称 nc,被誉为网络工具中的“瑞士军刀”,是网络调试与分析的利器。它的功能十分强大,然而平时我们经常使用的就是他的连通性测试功能,但是nc是被设计用来测试…...

面试复盘 part 02·1202-1207 日
作品集讲述部分 分析反思 作品集讲述部分,视觉讲述部分需要更换,需要换成其他视觉相关的修改 具体话术 这是一个信息展示优化方案,用户为财务,信息区分度不足,理解成本较高,因此选择需要降低理解成本。…...

Linux评估网络性能
网络性能直接影响应用程序对外提供服务的稳定性和可靠性 ping命令检测网络的连通性 如果网络反应缓慢,或连接中断,可以用ping来测试网络的连通情况 time值(单位为毫秒)显示了两台主机之间的网络延时情况。如果此值很大,则表示网络的延时很大…...

实战ansible-playbook(四) -文件操作重定向/追加
原始命令: ----------阶段1--------------- apt-get update -y apt install nano vim iputils-ping net-tools dialog gcc apt-utils make -y systemctl stop unattended-upgradessystemctl disable unattended-upgradesecho APT::Periodic::Update-Package-Lists "1&qu…...

简单题:1.两数之和
题目描述: 给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。 要求: 可以假设每种输入只会对应一个答案,并且你不能使用两次相同的元素…...