一、蓝牙通信技术

蓝牙技术是一种点对点点对面的网络构架,他可以在限制的范围内以很快的速度传输网络数据,在物联网应用中,支持网状网络的物联网短距离无线通信。目前它还被广泛用于智能可穿戴设备、智能门锁、智能医疗设备、智能照明设备、智能家电等消费电子、工业采集、汽车电子、智能建筑等所有的物联网智能产品中。

蓝牙是无线个人局域网,最初由爱立信制作,后来由蓝牙技术联盟制定了技术标准。蓝牙产品包括小型蓝牙模块,以及支持连接的蓝牙无线电和软件。 如果两台蓝牙设备想相互交流,则需要进行配对,一台设备将成为主设备,所有其他设备都将成为从设备。 通信时,主站侧需要进行检索并开始配对,如果构建链成功,则双方需要能够发送接收数据。在通信状态下,主侧和从侧的设备都开始切断,可以切断蓝牙链接。蓝牙通信本质上就是无线电传输技术,蓝牙的工作波段为2400–2483.5MHz(包括防护频带)。这是全球范围内无需取得执照(但并非无管制的)的工业、科学和医疗用(ISM)波段的 2.4 GHz 短距离无线电频段。

二、MCU及蓝牙模块

本文采用STM32F103C8T6的芯片及JDY-08 蓝牙透传模块,相关引脚如下:

MCU引脚设定:PA9、PA10作为USART1引脚,用于下载程序、调试显示,PA2、PA3作为USART2引脚,并与蓝牙模块进行通信,PA8作为GPIO_OUTPUT模式,用来控制蓝牙模块上的PWRC。

蓝牙模块为JDY-08 蓝牙透传模块,基于蓝牙 4.0 协议标准,工作频段为 2.4GHZ 范围,调制 方式为 GFSK,最大发射功率为 0db,最大发射距离 80 米,采用 TICC2541 芯片设计,支持用户通过 AT 命令修改设备名、服务 UUID、发射功率、配对密码等指令。

TICC2541 芯片 引脚:

引脚功能定义,在使用串口发送命令时,请将模块的 PWRC 引脚接地,并接上模块的电源(VCC、GND),电源电压为3~ 3.3V:

以及本文用到两个AT指令:

三、cubeMX配置MCU及蓝牙接口

本工程设计功能如下:

MCU(STM32F103C8T6)的引脚PA2、PA3的与蓝牙模块(TICC2541 )的11、12引脚连接,实现数据通信;MCU的PA8引脚与蓝牙模块的22引脚连接实现,实现蓝牙模块唤醒。

通信逻辑:电脑(com4)<->(Usart1)MCU(Usart2)<->蓝牙模块->手机(蓝牙调试器,需要开启手机蓝牙功能)。

功能:

  • 按键功能,用于按键时向蓝牙模块发送AT指令;
  • LED功能,用于接收蓝牙模块数据时做出闪灯响应;
  • 蓝牙功能,接收来自MCU端的串口通信,接收手机端的无线传输(即蓝牙通信);
  • 串口调试功能,MCU执行程序可以向Usart1发送信息到电脑端,既可实现日志输出,也可以实现指令转发到蓝牙模块。

【1】创建工程

1)新建stm32工程,选择芯片STM32F103C8T6

2)为工程命名完成创建

【2】CubeMX配置

1)开启sys mode接口

2)开启RCC

3)开启USART1(下载、调试)、USART2(连接蓝牙模块)。

4)开启串口USART1、USART2中断功能

5)串口引脚参数配置

6)蓝牙测试辅助接口及按键、LED灯GPIO引脚添加:

7)系统 时钟配置,直接拉满STM32F103C8T6能支持到的72MHz。

8)本工程配置页面保持默认,没有为每个外围设备驱动创建独立源文件,点击保持或生成代码按钮输出代码。

四、代码设计

【1】首先创建usart1接口的调试输出支持

1)禁用syscalls.c,右键选择该文件进入属性页面设置。

2)在工程目录下创建源码目录ICore,添加文件夹print及print.h/print.c,实现对系统printf函数的映射到usart1输出显示功能。

print.h

#ifndef INC_RETARGET_H_
#define INC_RETARGET_H_#include "stm32f1xx_hal.h"
#include "stdio.h"//用于printf函数串口重映射
#include <sys/stat.h>void ResetPrintInit(UART_HandleTypeDef  *huart);int _isatty(int fd);
int _write(int fd, char* ptr, int len);
int _close(int fd);
int _lseek(int fd, int ptr, int dir);
int _read(int fd, char* ptr, int len);
int _fstat(int fd, struct stat* st);#endif /* INC_RETARGET_H_ */

print.c

#include <_ansi.h>
#include <_syslist.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/times.h>
#include <limits.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>#include "print.h"#if !defined(OS_USE_SEMIHOSTING)
#define STDIN_FILENO  0
#define STDOUT_FILENO 1
#define STDERR_FILENO 2UART_HandleTypeDef *gHuart;void ResetPrintInit(UART_HandleTypeDef *huart)  {gHuart = huart;/* Disable I/O buffering for STDOUT  stream, so that* chars are sent out as soon as they are  printed. */setvbuf(stdout, NULL, _IONBF, 0);
}
int _isatty(int fd) {if (fd >= STDIN_FILENO && fd <=  STDERR_FILENO)return 1;errno = EBADF;return 0;
}
int _write(int fd, char* ptr, int len) {HAL_StatusTypeDef hstatus;if (fd == STDOUT_FILENO || fd ==  STDERR_FILENO) {hstatus = HAL_UART_Transmit(gHuart,  (uint8_t *) ptr, len, HAL_MAX_DELAY);if (hstatus == HAL_OK)return len;elsereturn EIO;}errno = EBADF;return -1;
}
int _close(int fd) {if (fd >= STDIN_FILENO && fd <=  STDERR_FILENO)return 0;errno = EBADF;return -1;
}
int _lseek(int fd, int ptr, int dir) {(void) fd;(void) ptr;(void) dir;errno = EBADF;return -1;
}
int _read(int fd, char* ptr, int len) {HAL_StatusTypeDef hstatus;if (fd == STDIN_FILENO) {hstatus = HAL_UART_Receive(gHuart,  (uint8_t *) ptr, 1, HAL_MAX_DELAY);if (hstatus == HAL_OK)return 1;elsereturn EIO;}errno = EBADF;return -1;
}
int _fstat(int fd, struct stat* st) {if (fd >= STDIN_FILENO && fd <=  STDERR_FILENO) {st->st_mode = S_IFCHR;return 0;}errno = EBADF;return 0;
}#endif //#if !defined(OS_USE_SEMIHOSTING)

【2】创建按键驱动、LED驱动、延时函数功能的支持

1)在ICore添加delay目录,并添加delay.h/delay.c源文件

delay.h

#ifndef DELAY_DELAY_H_
#define DELAY_DELAY_H_#include "stm32f1xx_hal.h" //HAL库文件声明
void delay_us(uint32_t us); //C文件中的函数声明#endif /* DELAY_DELAY_H_ */

delay.c

#include "delay.h"void delay_us(uint32_t us) //利用CPU循环实现的非精准应用的微秒延时函数
{uint32_t delay = (HAL_RCC_GetHCLKFreq() / 8000000 * us); //使用HAL_RCC_GetHCLKFreq()函数获取主频值,经算法得到1微秒的循环次数while (delay--); //循环delay次,达到1微秒延时
}

2)在ICore添加key目录,并添加key.h/key.c源文件

key.h

#ifndef KEY_KEY_H_
#define KEY_KEY_H_#include "stm32f1xx_hal.h" //HAL库文件声明
#include "main.h" //IO定义与初始化函数在main.c文件中,必须引用
#include "../delay/delay.h"uint8_t KEY_1(void);//按键1
uint8_t KEY_2(void);//按键2#endif /* KEY_KEY_H_ */

key.c

#include "key.h"uint8_t KEY_1(void)
{uint8_t a;a=0;//如果未进入按键处理,则返回0if(HAL_GPIO_ReadPin(GPIOA,KEY1_Pin)==GPIO_PIN_RESET){//读按键接口的电平
//      HAL_Delay(20);//延时去抖动(外部中断回调函数调用时不能使用系统自带的延时函数)delay_us(20000);//延时去抖动if(HAL_GPIO_ReadPin(GPIOA,KEY1_Pin)==GPIO_PIN_RESET){ //读按键接口的电平a=1;//进入按键处理,返回1}}while(HAL_GPIO_ReadPin(GPIOA,KEY1_Pin)==GPIO_PIN_RESET); //等待按键松开delay_us(20000);//延时去抖动(避开按键放开时的抖动)return a;
}uint8_t KEY_2(void)
{uint8_t a;a=0;//如果未进入按键处理,则返回0if(HAL_GPIO_ReadPin(GPIOA,KEY2_Pin)==GPIO_PIN_RESET){//读按键接口的电平
//      HAL_Delay(20);//延时去抖动(外部中断回调函数调用时不能使用系统自带的延时函数)delay_us(20000);//延时去抖动if(HAL_GPIO_ReadPin(GPIOA,KEY2_Pin)==GPIO_PIN_RESET){ //读按键接口的电平a=1;//进入按键处理,返回1}}while(HAL_GPIO_ReadPin(GPIOA,KEY2_Pin)==GPIO_PIN_RESET); //等待按键松开delay_us(20000);//延时去抖动(避开按键放开时的抖动)return a;
}

3)在ICore添加led目录,并添加led.h/led.c源文件

key.h

#ifndef LED_LED_H_
#define LED_LED_H_#include "stm32f1xx_hal.h" //HAL库文件声明
#include "main.h" //IO定义与初始化函数在main.c文件中,必须引用void LED_1(uint8_t a);//LED1独立控制函数(0为熄灭,其他值为点亮)
void LED_2(uint8_t a);//LED2独立控制函数(0为熄灭,其他值为点亮)
void LED_ALL(uint8_t a);//LED1~4整组操作函数(低4位的1/0状态对应4个LED亮灭,最低位对应LED1)
void LED_1_Contrary(void);//LED1状态取反
void LED_2_Contrary(void);//LED2状态取反#endif /* LED_LED_H_ */

key.c

#include "led.h"void LED_1(uint8_t a)//LED1独立控制函数(0为熄灭,其他值为点亮)
{if(a)HAL_GPIO_WritePin(GPIOB,LED1_Pin,GPIO_PIN_SET);else HAL_GPIO_WritePin(GPIOB,LED1_Pin,GPIO_PIN_RESET);
}
void LED_2(uint8_t a)//LED2独立控制函数(0为熄灭,其他值为点亮)
{if(a)HAL_GPIO_WritePin(GPIOB,LED2_Pin,GPIO_PIN_SET);else HAL_GPIO_WritePin(GPIOB,LED2_Pin,GPIO_PIN_RESET);
}
void LED_ALL(uint8_t a)//LED1~2整组操作函数(低2位的1/0状态对应2个LED亮灭,最低位对应LED1)
{if(a&0x01)HAL_GPIO_WritePin(GPIOB,LED1_Pin,GPIO_PIN_SET);else HAL_GPIO_WritePin(GPIOB,LED1_Pin,GPIO_PIN_RESET);if(a&0x02)HAL_GPIO_WritePin(GPIOB,LED2_Pin,GPIO_PIN_SET);else HAL_GPIO_WritePin(GPIOB,LED2_Pin,GPIO_PIN_RESET);
}
void LED_1_Contrary(void){HAL_GPIO_WritePin(GPIOB,LED1_Pin,1-HAL_GPIO_ReadPin(GPIOB,LED1_Pin));
}
void LED_2_Contrary(void){HAL_GPIO_WritePin(GPIOB,LED2_Pin,1-HAL_GPIO_ReadPin(GPIOB,LED2_Pin));
}

【3】创建串口驱动程序,主要是复写串口回调功能

1)在ICore添加usart目录,并添加usart.h/usart.c源文件,实现串口驱动功能

usart.h

#ifndef INC_USART_H_
#define INC_USART_H_#include "stm32f1xx_hal.h" //HAL库文件声明
#include <string.h>//用于字符串处理的库
#include "../print/print.h"//用于printf函数串口重映射extern UART_HandleTypeDef huart1;//声明USART1的HAL库结构体
extern UART_HandleTypeDef huart2;//声明USART2的HAL库结构体#define USART1_REC_LEN  200//定义USART1最大接收字节数
#define USART2_REC_LEN  200//定义USART1最大接收字节数extern uint8_t  USART1_RX_BUF[USART1_REC_LEN];//接收缓冲,最大USART_REC_LEN个字节.末字节为换行符
extern uint16_t USART1_RX_STA;//接收状态标记
extern uint8_t USART1_NewData;//当前串口中断接收的1个字节数据的缓存extern uint8_t  USART2_RX_BUF[USART2_REC_LEN];//接收缓冲,最大USART_REC_LEN个字节.末字节为换行符
extern uint16_t USART2_RX_STA;//接收状态标记
extern uint8_t USART2_NewData;//当前串口中断接收的1个字节数据的缓存void  HAL_UART_RxCpltCallback(UART_HandleTypeDef  *huart);//串口中断回调函数声明#endif /* INC_USART_H_ */

usart.c

#include "usart.h"uint8_t USART1_RX_BUF[USART1_REC_LEN];//接收缓冲,最大USART_REC_LEN个字节.
/** bit15:接收到回车(0x0d)时设置HLPUSART_RX_STA|=0x8000;* bit14:接收溢出标志,数据超出缓存长度时,设置HLPUSART_RX_STA|=0x4000;* bit13:预留* bit12:预留* bit11~0:接收到的有效字节数目(0~4095)*/
uint16_t USART1_RX_STA=0;
uint8_t USART1_NewData;//当前串口中断接收的1个字节数据的缓存uint8_t USART2_RX_BUF[USART2_REC_LEN];
uint16_t USART2_RX_STA=0;
uint8_t USART2_NewData;void  HAL_UART_RxCpltCallback(UART_HandleTypeDef  *huart)//串口中断回调函数
{if(huart ==&huart1)//判断中断来源(串口1:USB转串口){
//      printf("%c",USART1_NewData); //测试用,把收到的数据以 a符号变量 发送回电脑if(USART1_NewData==0x0d){//回车标记USART1_RX_STA|=0x8000;//标记接到回车}else{if((USART1_RX_STA&0X0FFF)<USART1_REC_LEN){USART1_RX_BUF[USART1_RX_STA&0X0FFF]=USART1_NewData; //将收到的数据放入数组USART1_RX_STA++;  //数据长度计数加1}else{USART1_RX_STA|=0x4000;//数据超出缓存长度,标记溢出}}HAL_UART_Receive_IT(&huart1,(uint8_t *)&USART1_NewData,1); //再开启接收中断}if(huart ==&huart2)//判断中断来源(串口2:BT模块){
//      printf("%c",USART2_NewData); //测试用,把收到的数据以 a符号变量 发送回电脑if(USART2_NewData==0x0d||USART2_NewData==0x0A){//回车标记,(手机APP“蓝牙调试器”回复数据以0x5A为结束符)USART2_RX_STA|=0x8000;//标记接到回车}else{if((USART2_RX_STA&0X0FFF)<USART2_REC_LEN){USART2_RX_BUF[USART2_RX_STA&0X0FFF]=USART2_NewData; //将收到的数据放入数组USART2_RX_STA++;  //数据长度计数加1}else{USART2_RX_STA|=0x4000;//数据超出缓存长度,标记溢出}}HAL_UART_Receive_IT(&huart2,(uint8_t *)&USART2_NewData,1); //再开启接收中断}
}

【4】创建蓝牙驱动

该驱动主要实现通过usart2向蓝牙模块写入数据,(读取数据主要通过串口usart2回调,在usart.c中实现)。在ICore添加bt目录,并添加bt.h/bt.c源文件,实现蓝牙驱动功能

bt.h

#ifndef BT_BT_H_
#define BT_BT_H_#include "stm32f1xx_hal.h" //HAL库文件声明
#include "main.h"
#include "../usart/usart.h"
#include "../delay/delay.h"
#include <string.h>//用于字符串处理的库
#include <stdarg.h>
#include <stdlib.h>
#include "stdio.h"extern UART_HandleTypeDef huart2;//声明UART2的HAL库结构体
void BT_WEEKUP (void);//蓝牙模块唤醒函数
void BT_printf (char *fmt, ...); //BT蓝牙模块发送#endif /* BT_BT_H_ */

bt.c

#include "bt.h"//蓝牙模块唤醒函数
//对蓝牙模块上的PWRC(P00)接口一个低电平脉冲,如不使用睡眠模式可忽略此函数
void BT_WEEKUP (void)
{HAL_GPIO_WritePin(BT_RE_GPIO_Port,BT_RE_Pin, GPIO_PIN_RESET);//PWRC接口控制delay_us(100);HAL_GPIO_WritePin(BT_RE_GPIO_Port,BT_RE_Pin, GPIO_PIN_SET);//PWRC接口控制
}
//蓝牙模块通信,使用UART2,这是BT蓝牙的printf函数
//调用方法:BT_printf("123"); //向UART2发送字符123
void BT_printf (char *fmt, ...)
{char buff[USART2_REC_LEN+1];  //用于存放转换后的数据 [长度]uint16_t i=0;va_list arg_ptr;va_start(arg_ptr, fmt);vsnprintf(buff, USART2_REC_LEN+1, fmt,  arg_ptr);//数据转换i=strlen(buff);//得出数据长度if(strlen(buff)>USART2_REC_LEN)i=USART2_REC_LEN;//如果长度大于最大值,则长度等于最大值(多出部分忽略)HAL_UART_Transmit(&huart2,(uint8_t  *)buff,i,0xffff);//串口发送函数(串口号,内容,数量,溢出时间)va_end(arg_ptr);
}
//所有USART串口的中断回调函数HAL_UART_RxCpltCallback,统一存放在USART.C文件中。

五、编译及测试

【1】功能调用及编译

1)在main.c文件中进行蓝牙功能调用实现,部分源码如下:

/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "../../ICore/led/led.h"
#include "../../ICore/key/key.h"
#include "../../ICore/delay/delay.h"
#include "../../ICore/print/print.h"//用于printf函数串口重映射
#include "../../ICore/bt/bt.h"
/* USER CODE END Includes *//* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD *//* USER CODE END PTD *//* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD *//* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM *//* USER CODE END PM *//* Private variables ---------------------------------------------------------*/
UART_HandleTypeDef huart1;
UART_HandleTypeDef huart2;/* USER CODE BEGIN PV *//* USER CODE END PV *//* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART1_UART_Init(void);
static void MX_USART2_UART_Init(void);
/* USER CODE BEGIN PFP *//* USER CODE END PFP *//* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 *//* USER CODE END 0 *//*** @brief  The application entry point.* @retval int*/
int main(void)
{/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();MX_USART1_UART_Init();MX_USART2_UART_Init();/* USER CODE BEGIN 2 */ResetPrintInit(&huart1);//将printf()函数映射到UART1串口上HAL_UART_Receive_IT(&huart1,(uint8_t *)&USART1_NewData,1);//开启串口1接收中断HAL_UART_Receive_IT(&huart2,(uint8_t *)&USART2_NewData,1); //再开启串口3接收中断/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){//demo 蓝牙02if(USART2_RX_STA&0xC000){//判断中断接收标志位(蓝牙模块BT,使用USART2)BT_printf("%c",USART2_RX_STA);if((USART2_RX_STA&0x7FFF) == 1)   //判断接收数量1个(手机控制程序){BT_printf("%c",USART2_RX_BUF[0]);switch (USART2_RX_BUF[0]){//判断接收数据的内容case 0x41:LED_1(1);//LED1控制BT_printf("Relay ON");//返回数据内容,在手机APP上显示break;case 0x44:LED_1(0);//LED1控制BT_printf("Relay OFF");//返回数据内容,在手机APP上显示break;case 0x42:LED_2(1);//LED1控制BT_printf("LED1 ON");//返回数据内容,在手机APP上显示break;case 0x45:LED_2(0);//LED1控制BT_printf("LED1 OFF");//返回数据内容,在手机APP上显示break;case 0x43:LED_1(0);//LED1控制LED_2(0);//LED1控制BT_printf("BEEP");//返回数据内容,在手机APP上显示break;case 0x46:BT_printf("CPU Reset");//返回数据内容,在手机APP上显示HAL_Delay(1000);//延时NVIC_SystemReset();//系统软件复位函数break;default://冗余语句break;}}printf("%.*s\r\n", USART2_RX_STA&0X0FFF, USART2_RX_BUF);//BT接收内容,转发usart1USART2_RX_STA=0;//标志位清0,准备下次接收}//接收到电脑发送给(usart1)数据,转身将其发送到给usart2,进而实现送数据给BT模块if(USART1_RX_STA&0xC000){//结束标记BT_printf("%.*s\r\n",USART1_RX_STA&0X0FFF, USART1_RX_BUF);USART1_RX_STA=0;//接收重新开始HAL_Delay(100);//等待}if(KEY_1())//按下KEY1判断{LED_1(1);//LED1控制 //在蓝牙模块回复之前先将LED状态复位LED_2(0);//LED2控制BT_printf("AT+NAMEPYFREEBT");//向蓝牙模块发送AT指令(修改模块的广播名为PYFREEBT)}if(KEY_2())//按下KEY2判断{LED_1(0);//LED1控制 //在蓝牙模块回复之前先将LED状态复位LED_2(1);//LED2控制BT_printf("AT+DISC");//向蓝牙模块发送AT指令(断开与手机的连接)}/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}/* USER CODE END 3 */
}

2)设置编译输出支持,右键工程进入项目属性设置页面:

3)点击编译按钮,完成编译(整个工程需要源码修改或添加的源文件如下):

【2】程序测试

1)测试过程需要三个工具文件支持,读者可以自网上搜索最新版本或采用其他同功能工具替代测试:

FlyMCU加载工具,将生成的.hex程序文件加载到板子上

SSCOM5串口工具,连接MCU的USART1,实现调试信息显示及下行指令输入

蓝牙调试器工具,本文用的是1.9安卓版本。

后续补充,应读者要求,提供CSDN下载链接:        https://download.csdn.net/download/py8105/87174936

2)加载程序,选择串口,选择程序(.hex),点击开始编程按钮:

3)手机打开蓝牙调试器(别忘了开启手机蓝牙功能),进入界面,搜索蓝牙,点击蓝牙边上“+”按钮连接蓝牙模块,采用SSCOM串口工具连接到usart1上,就可以通过蓝牙通信实现手机(蓝牙调试器)与电脑(串口工具)的通信了,在蓝牙调试器发送数据时,十六进制时需要加上“0A”作为结尾,如果十进制发送时,注意加上换行再发送:

注:本文连接前,点击开发板的按键1更改了蓝牙名称PYFREEBT:

if(KEY_1())//按下KEY1判断{LED_1(1);//LED1控制 //在蓝牙模块回复之前先将LED状态复位LED_2(0);//LED2控制BT_printf("AT+NAMEPYFREEBT");//向蓝牙模块发送AT指令(修改模块的广播名为PYFREEBT)}

串口发送数据:

可以进入按钮控制页面进行指令定制设置

至此实现了MCU(STM32F103C8T6)通过蓝牙模块与外界设备进行通信,另外通过AT指令也可以控制蓝牙模块。

STM32CubeIDE开发(二十五), 物联网应用之stm32的蓝牙通信设计相关推荐

  1. STM32CubeIDE开发(二十九), 如何结合FreeRTOS开发STM32程序

    目录 一.STM32CubeIDE使用内置的FreeRTOS 二.创建使用FreeRTOS系统的STM32CubeIDE工程 三.使用FreeRTOS功能 四.编译及测试 一.STM32CubeIDE ...

  2. STM32CubeIDE开发(二十二), stm32的RS485/232串口通信开发要点

    一.stm32串口通信 stm32串口通信一般是指通过UART(Universal Asynchronous Receiver/Transmitter)通用异步收发传输器传输数据,UART 作为异步串 ...

  3. STM32CubeIDE开发(二十六), STM32的CAN总线开发要点

    一.CAN总线简介 1.1 CAN概述 CAN是Controller Area Network(控制区域网络) 的缩写,是ISO国际标准化的串行通信协议.由德国电气商博世公司在1986年率先提出.此后 ...

  4. 【Android游戏开发二十五】在Android上的使用《贝赛尔曲线》!

    首先对于<赛贝尔曲线>不是很了解的童鞋,请自觉白度百科.google等等... 为了方便偷懒的童鞋,这里给个<贝赛尔曲线>百科地址,以及一段话简述<贝赛尔曲线>: ...

  5. SQL2K数据库开发二十六之存储过程操作创建存储过程(一)

    1.可以使用Transact-SQL中的CREATE PROCEDURE语句创建存储过程,使用该语句的语法为: 2.在查询分析器中执行如下语句创建一个存储过程. 3.在企业管理器中创建存储过程的方法为 ...

  6. 二十五岁零基础转行做软件测试怎么样?

    俗话说得好:男怕入错行,女怕嫁错郎,那么你的入行方向决定着你的整个职业发展!! 所以在考虑要进入什么行业之前,必须要了解清楚这个行业的发展前景怎么样? 我们都知道,随着社会的发展,互联网行业涉及也越来 ...

  7. 未处理异常和C++异常——Windows核心编程学习手札之二十五

    未处理异常和C++异常 --Windows核心编程学习手札之二十五 当一个异常过滤器返回EXCEPTION_CONTINUE_SEARCH标识符时是告诉系统继续上溯调用树,寻找另外的异常过滤器,但当每 ...

  8. linux exec 二程序,二十五、Linux 进程与信号---exec函数

    25.1 介绍 在用 fork 函数创建子进程后,子进程往往要调用一种 exec 函数以执行另一个程序 当进程调用一种 exec 函数时,该进程完全由新程序代换,替换原有进程的正文,而新程序则从其 m ...

  9. SAP UI5 初学者教程之二十五 - 使用代理服务器解决 SAP UI5 应用访问远端 OData 服务的跨域问题试读版

    一套适合 SAP UI5 初学者循序渐进的学习教程 教程目录 SAP UI5 本地开发环境的搭建 SAP UI5 初学者教程之一:Hello World SAP UI5 初学者教程之二:SAP UI5 ...

最新文章

  1. 5G 行业专网 — 公有云上的 5G 专网
  2. MyBatis代码生成器-Example讲解
  3. Mac 下安装mysqldb 问题:一条命令解决mysql_config not found
  4. Oracle数据库 查看表是否是 索引组织表的方法
  5. 大厂出品免费图标资源站
  6. (九十)使用多个storyboard+代码实现控制器的分开管理
  7. ML《集成学习(三)Boosting和Adaboosting回归树》
  8. [BZOJ4521][Cqoi2016]手机号码 (数位dp)
  9. Linux查找树莓派ip地址,让树莓派“说”出自己的IP地址
  10. 关于如何修改CSDN中的字体大小和颜色
  11. html标签种类很多,为什么不都用div?
  12. 学生通讯录管理系统的设计与实现
  13. Python房贷计算器GUI(等额本息,等额本金)
  14. 工业镜头倍率及视场范围、焦距的计算方法
  15. 06年及以前韩国星际职业联赛及选手资料
  16. Mysql 5.5.8 安装手册
  17. java博客推荐(收集好的博客)
  18. 计算机相关专业术语中英文对照
  19. winXP安装FTP及连接FTP
  20. centos7 linux ffmpeg 改变 修改 视频 帧频 shell 懒人系列-17

热门文章

  1. CDH安装Spark2
  2. QQ登录界面测试用例
  3. dcs world f15c教学_DCS信号干扰原因分析及解决方法,收藏备用!
  4. oracle时间24小时格式转换,在oracle数据库中查询时间并转为24小时制--------------String转Date类型或者Date转String类型...
  5. java -jar xx.jar是如何运行的
  6. 阿里传奇工程师多隆的程序世界
  7. poj 2751 双机调度问题Johnson算法(贪心)
  8. STM32基于HAL库自由启动和关闭定时器:
  9. [Matlab脚本]如何解析标准CAN报文
  10. 四个步骤实现在ESRI ArcMap中加载17.6G离线卫星地图的方法