stm32攻略(随时更新,更新时间:2023.5.5)
目录
1 CubeMX基本配置(针对stm32F407ZGT6,时钟树的配置需要根据单片机的种类而定)
2 接线
2.1 STM32F407ZG单片机连接ST_LINK
2.2 STM32F407ZG单片机连接USB转TTL(用于串口通信)
3 串口通信(附加中断+定时器+PWM综合)
3.1 printf/scanf的重定向
3.2 HAL_UART_Transmit()和HAL_UART_Receive()函数
3.3 中断及中断回调函数
3.3.1 中断函数
3.3.2 中断回调函数
3.4 DMA
3.5 综合基础知识,通过串口通信控制
4 舵机
4.1 相关计算
4.2 接线
5 PID控制算法
5.1 简介
5.2 比例Proportional
5.3 积分Integral
5.4 微分Differential
5.5 公式
5.6 积分限幅
5.7 积分限行
5.8 相关代码
6 systick(定时器,多用于延时)
6.1 寄存器
6.2 代码
7 蓝牙模块
1 CubeMX基本配置(针对stm32F407ZGT6,时钟树的配置需要根据单片机的种类而定)
2 接线
2.1 STM32F407ZG单片机连接ST_LINK
单片机 ST_LINK
9--------------------6
7--------------------2
20------------------3/4
1--------------------7/8
这里附上具体的接线图片:
2.2 STM32F407ZG单片机连接USB转TTL(用于串口通信)
单片机 USB转TTL
TX————RXD
RX————TXD
GND————GND
5V————5V
3 串口通信(附加中断+定时器+PWM综合)
3.1 printf/scanf的重定向
int fputc(int c,FILE *stream)//printf
{uint8_t ch[1]={c};HAL_UART_Transmit(&huart1,ch,1,0xFFFF);return c;
}int fgetc(FILE *stream)//scanf
{uint8_t ch[1];HAL_UART_Receive(&huart1,ch,1,0xFFFF);return ch[0];
}
3.2 HAL_UART_Transmit()和HAL_UART_Receive()函数
HAL_UART_Transmit()是HAL库中的一个函数,用于向UART发送数据。该函数需要传入UART句柄、发送数据的缓冲区指针和发送数据的长度作为参数。在调用该函数时,UART会将缓冲区中的数据发送出去。如果发送成功,该函数会返回HAL_OK,否则会返回错误码。
参数1:使用的串口,2:要发送的数据,3:数据大小,4:发送的超时时间HAL_UART_Transmit(&huart1,Data,sizeof(Data),1000);
HAL_UART_Receive()函数同理,不再赘述
注意:这种发送方式是阻塞式(阻塞模式就像是一个延时函数,当这个函数没处理完那么,所有的按照流程需要执行的代码都不会被执行,要等到这个延时完成,类似 平时看书上写的LED灯闪烁,用的delay()一样。而非阻塞模式就像他定义的那样,一般用的是中断,执行这条语句的时候,开启相应的中断达到一定的条件才进行处理,这样不会影响到流程的执行.我的理解就是,阻塞就是死等,非阻塞就是中断)
3.3 中断及中断回调函数
3.3.1 中断函数
HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
HAL_UART_Receive_IT()函数同理
3.3.2 中断回调函数
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{}void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{HAL_UART_Transmit_IT(&huart1,buffer,100);HAL_UART_Receive_IT(&huart1,buffer,100);
}
3.4 DMA
DMA,全称Direct Memory Access,即直接存储器访问。
DMA传输将数据从一个地址空间复制到另一个地址空间,提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。
我们知道CPU有转移数据、计算、控制程序转移等很多功能,系统运作的核心就是CPU,
CPU无时不刻的在处理着大量的事务,但有些事情却没有那么重要,比方说数据的复制和存储数据,如果我们把这部分的CPU资源拿出来,让CPU去处理其他的复杂计算事务,是不是能够更好的利用CPU的资源呢?
因此:转移数据(尤其是转移大量数据)是可以不需要CPU参与。比如希望外设A的数据拷贝到外设B,只要给两种外设提供一条数据通路,直接让数据由A拷贝到B 不经过CPU的处理,
DMA就是基于以上设想设计的,它的作用就是解决大量数据转移过度消耗CPU资源的问题。有了DMA使CPU更专注于更加实用的操作–计算、控制等。
HAL_UART_Receive_DMA(&huart1,buffer,100);__HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE);
注意:如果要想能够保证不止一次输入数据,需要在回调函数里写内容(放在it文件里)
void USART1_IRQHandler(void)
{/* USER CODE BEGIN USART1_IRQn 0 */if(__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE)!=RESET){__HAL_UART_CLEAR_IDLEFLAG(&huart1);HAL_UART_DMAStop(&huart1);//len=100-__HAL_DMA_GET_COUNTER(huart1.hdmarx);//rintf("%d\r\n",len);*/}/* USER CODE END USART1_IRQn 0 */HAL_UART_IRQHandler(&huart1);/* USER CODE BEGIN USART1_IRQn 1 *//* USER CODE END USART1_IRQn 1 */
}
3.5 综合基础知识,通过串口通信控制
实现功能如下:
1.LED灯的亮灭
2.定时器中断控制LED灯按频率闪烁
3.PWM波控制呼吸灯
4.PWM波控制舵机转动
5.按键控制灯的亮灭
6.高电平控制蜂鸣器(注意蜂鸣器声音挺大的,第一次用的时候吓一跳)
注意事项:
1.头文件加一个stdio.h,因为用到了printf和scanf,并且需要重定向(这两个函数原本是在显示屏上进行的)
2.最好定义全局变量,防止值的改变
3.利用中断控制时在CubeMX配置时要注意打开global interrupt选项
4.我的单片机PF9和PF10引脚对应两个LED灯
5.PWM波在Keil编写程序时要加上Start函数打开PWM波
6.我加的printf(check)是用来检验程序是否正常运行
7.在使用PWM波控制呼吸灯时要看好灯对应的那个引脚连接了哪个定时器
8.在使用PWM波控制舵机时要看好自己开的定时器对应哪个引脚,插信号线要插对
9.有关舵机的具体计算在下面有,可以先看下面的再回来看
10.输入数据到buffer【0】的位置来控制程序
11.如果不加DMA_Stop()函数则后续输入的数据会累积到buffer【1】【2】等等,这样if判断句就没用了
12.windows换行的话需要同时写\r\n
13.按键和亮灯原理:(我的单片机KEY1对应PE3,KEY0对应PE4)
14.按键达不到预期效果(PF9定时器占用了),意会即可
这样算是用到了所有stm32的基础知识,包括:
1.GPIO控制高低电平
2.定时器中断
3.PWM波控制
4.串口通信(阻塞、非阻塞、DMA)
CubeMX整体配置:
代码:
/* USER CODE BEGIN Header */
/********************************************************************************* @file : main.c* @brief : Main program body******************************************************************************* @attention** <h2><center>© Copyright (c) 2023 STMicroelectronics.* All rights reserved.</center></h2>** This software component is licensed by ST under BSD 3-Clause license,* the "License"; You may not use this file except in compliance with the* License. You may obtain a copy of the License at:* opensource.org/licenses/BSD-3-Clause********************************************************************************/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "dma.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"
#include "stdio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
uint8_t buffer[100];
uint8_t len;
/* 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 ---------------------------------------------------------*//* USER CODE BEGIN PV *//* USER CODE END PV *//* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP *//* USER CODE END PFP *//* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
int fputc(int c,FILE *stream)//printf
{uint8_t ch[1]={c};HAL_UART_Transmit(&huart1,ch,1,0xFFFF);return c;
}int fgetc(FILE *stream)//scanf
{uint8_t ch[1];HAL_UART_Receive(&huart1,ch,1,0xFFFF);return ch[0];
}void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{}void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{HAL_UART_Transmit_DMA(&huart1,buffer,100);HAL_UART_Receive_DMA(&huart1,buffer,100);
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{HAL_GPIO_TogglePin(GPIOF,GPIO_PIN_10);
}
/* 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_DMA_Init();MX_USART1_UART_Init();MX_TIM14_Init();MX_TIM2_Init();MX_TIM3_Init();MX_USART2_UART_Init();/* USER CODE BEGIN 2 */HAL_TIM_PWM_Start(&htim14,TIM_CHANNEL_1);HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_1);HAL_GPIO_WritePin(GPIOF,GPIO_PIN_9,GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOF,GPIO_PIN_10,GPIO_PIN_SET);/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 *///HAL_UART_Transmit(&huart1,"HELLO",5,0xFFFF);//uint8_t buffer[100];HAL_UART_Receive_DMA(&huart1,buffer,100);__HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE);//printf("check0\r\n");printf("%d\r\n",buffer[0]);HAL_Delay(1000);if(buffer[0]==1){printf("check1\r\n");HAL_GPIO_WritePin(GPIOF,GPIO_PIN_9,GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOF,GPIO_PIN_10,GPIO_PIN_RESET);HAL_Delay(500);printf("check2\r\n");HAL_Delay(1000);//memset(buffer,0,sizeof(buffer));}if(buffer[0]==2){printf("check3\r\n");HAL_GPIO_WritePin(GPIOF,GPIO_PIN_9,GPIO_PIN_RESET);HAL_GPIO_WritePin(GPIOF,GPIO_PIN_10,GPIO_PIN_SET);HAL_Delay(500);printf("check4\r\n");HAL_Delay(1000);//memset(buffer,0,sizeof(buffer));}if(buffer[0]==3){printf("check5\r\n");for(uint16_t cnt=0;cnt<1000;cnt++){__HAL_TIM_SetCompare(&htim14,TIM_CHANNEL_1,cnt);HAL_Delay(1);}for(uint16_t cnt=1000;cnt>0;cnt--){__HAL_TIM_SetCompare(&htim14,TIM_CHANNEL_1,cnt);HAL_Delay(1);}printf("check6\r\n");HAL_Delay(1000);}if(buffer[0]==4){printf("check7\r\n");HAL_TIM_Base_Start_IT(&htim2);printf("check8\r\n");HAL_Delay(1000);}if(buffer[0]==5){printf("check9\r\n");for(uint16_t cnt=500;cnt<=2500;cnt++){__HAL_TIM_SetCompare(&htim3,TIM_CHANNEL_1,cnt);HAL_Delay(1);}for(uint16_t cnt=2500;cnt>=500;cnt--){__HAL_TIM_SetCompare(&htim3,TIM_CHANNEL_1,cnt);HAL_Delay(1);}printf("check10\r\n");HAL_Delay(1000);}if(buffer[0]==6){printf("check11\r\n");if(HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_4)==RESET){HAL_GPIO_WritePin(GPIOF,GPIO_PIN_9,GPIO_PIN_SET);printf("check12\r\n");}if(HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_4)==SET){HAL_GPIO_WritePin(GPIOF,GPIO_PIN_9,GPIO_PIN_RESET);printf("check13\r\n");}if(HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_3)==RESET){HAL_GPIO_WritePin(GPIOF,GPIO_PIN_10,GPIO_PIN_SET);printf("check14\r\n");}if(HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_3)==SET){HAL_GPIO_WritePin(GPIOF,GPIO_PIN_10,GPIO_PIN_RESET);printf("check15\r\n");}printf("check16\r\n");HAL_Delay(1000);}if(buffer[0]==7) ){printf("check17\r\n");HAL_GPIO_WritePin(GPIOF,GPIO_PIN_8,GPIO_PIN_SET);HAL_Delay(500);HAL_GPIO_WritePin(GPIOF,GPIO_PIN_8,GPIO_PIN_RESET);HAL_Delay(500);printf("check18\r\n");}/*if(buffer[0]!='\0'){printf("%s\r\n",buffer);memset(buffer,0,sizeof(buffer));printf("%d\r\n",len);}*/HAL_Delay(100);/*uint8_t SendBuffer[30]={"hello,world!"};HAL_UART_Transmit(&huart2, (uint8_t *)SendBuffer, sizeof(SendBuffer), HAL_MAX_DELAY);*/}/* USER CODE END 3 */
}
4 舵机
4.1 相关计算
我们打开TIM3定时器,这个定时器是挂在APB1总线上的,根据配置好的时钟树可知
频率是84MHz
然后为了方便计算,我们把分频系数设置成84-1,这样相当于1秒钟点1000000次
由于舵机的驱动信号是50Hz,周期是0.02s,所以在一个周期内会点20000次
舵机的转动角度是按照高电平的占空比来计算的
经过手算,我们可以大致推出角度和比较值之间的关系,舵机的难点也就在这了
4.2 接线
舵机 单片机
信号线(黄)-------PA6(根据自己的定时器而定)
电源线(红)-------ST-LINK上的5V(9/10)
地线(棕)----------GND
5 PID控制算法
5.1 简介
PID控制中有P、I、D三个参数,PID即:Proportional(比例)、Integral(积分)、Differential(微分)的缩写。只有明白这三个参数的含义和作用才能完成控制器PID参数整定,让控制器到达最佳控制效果。
PID是经典的闭环控制算法,具有原理简单,易于实现,适用面广,控制参数相互独立,参数的选定比较简单等优点。
凡是需要将某一个物理量“保持稳定”的场合(比如维持平衡,稳定温度、转速等),PID都会派上大用场。
5.2 比例Proportional
比例控制器实际上就是个放大倍数可调的放大器,即△P=Kp×e,式中Kp为比例增益,即Kp可大于1,也可小于1;e为控制器的输入,也就是测量值与给定值之差,又称为偏差。
比例控制有个缺点,就是会产生余差,要克服余差就必须引入积分作用。
只有比例系数无法准确到达目标位置,但增大比例系数有利于减小误差
5.3 积分Integral
控制器的积分作用就是为了消除自控系统的余差而设置的。所谓积分,就是随时间进行累积的意思,即当有偏差输入e存在时,积分控制器就要将偏差随时间不断累积起来,也就是积分累积的快慢与偏差e的大小和积分速度成正比。只要有偏差e存在,积分控制器的输出就要改变,也就是说积分总是起作用的,只有偏差不存在时,积分才会停止。
实际上积分作用很少单独使用,通常与比例作用一起使用,使其既具有把偏差放大(或缩小)的比例作用,又具有将偏差随时间累积的积分作用,且其作用方向是一致的。这时控制器的输出为:△P=Ke+△Pi,式中△P为控制器输出值的变化;Ke为比例作用引起的输出;△Pi为积分作用引起的输出。
同时使用比例系数和积分可以准确到达目标位置,但当比例系数过大时会出现不稳定性
5.4 微分Differential
微分作用主要是用来克服被控对象的滞后,常用于温度控制系统。除采用微分作用外,在使用控制系统时要注意测量传送的滞后问题,如温度测量元件的选择和安装位置等。
在常规PID控制器中,微分作用的输出变化与微分时间和偏差变化的速度成比例,而与偏差的大小无关,偏差变化的速度越大,微分时间越长,则微分作用的输出变化越大。但如果微分作用过强,则可能由于变化太快而由其自身引起振荡,使控制器输出中产生明显的“尖峰”或“突跳”。为了避免这一扰动,在PID调节器和DCS中可使用微分先行PID运算规律,即只对测量值PV进行微分,当人工改变控制器的给定值SP时,不会造成控制器输出的突变,避免了改变SP的瞬间给控制系统带来的扰动。如TDC-3000,则在常规PID算法中增加一个软开关,组态时供用户选择控制器对偏差、还是测量值进行微分。
微分保证系统能够平稳运行,不至于出现太大的波动
5.5 公式
连续形式:
离散形式(常用,由连续形式推导):
5.6 积分限幅
试想一下,使用P和I项进行控制,无人机在地面准备起飞,期望高度是100m。此时一个人摁住无人机,那么误差值一直为100m,控制器P项输出保持不变,控制器I项输出是线性增长的
一段时间后,那个人突然不摁了,此时控制器I项输出可能非常大,再加上控制器P项输出,控制器给电机的输出非常大,那么无人机速度就非常快并且飞的非常高。对于这种情况,我们对积分限幅,I项增加到一定值时就不再增了。那么无人机在上面这种情况下就不至于飞的很快很高,这就是积分限幅的作用。
5.7 积分限行
我们直接将传感器的反馈值分出来一路给到控制器的D项,这样做有一个好处就是如果希望无人机快速反应移动,当期望高度突变的时候,影响会先给到P和I项,由于开始时无人机位置没有突变,传感器反馈的实际高度值也不会突变,因此不会马上给到D项,这样就有效减小了D项开始的缓冲作用,使无人机可以快速反应移动。如果不这样做,那么如果期望高度突变,D项的微分值也会突变变得很大,缓冲作用非常大,使相应效果大大降低。
5.8 相关代码
chassis_motor_pid[i].SpeedPID.current=motor_chassis[i].speed_rpm;
pid_calc(&chassis_motor_pid[i].SpeedPID);void pid_calc(_pid* pid)
{pid->e=pid->target-pid->current;pid->p_out=(int32_t)(pid->Kp*pid->e);if(fabs(pid->e)<I_Band)//积分限幅和积分分离 {pid->i_out+=(int32_t)(pid->Ki*pid->e);limit(&(pid->i_out),pid->IntegralLimit);}else{pid->i_out=0;}pid->d_out=(int32_t)(pid->Kd*(pid->e-pid->last_e));pid->total_out=pid->p_out+pid->i_out+pid->d_out;//公式 limit(&(pid->total_out),pid->MaxOutput);//输出限制 pid->last_e=pid->e;//更新last值 }
6 systick(定时器,多用于延时)
6.1 寄存器
Systick的寄存器分为:
CTRL
LOAD
VAL
CALIB
ENABLE位就是开关Systick
TICKINT的作用是当写入的值为"1"时,会进入SysTick_Handler()中断服务函数,随后执行用户代码。
CLKSOURCE该位要联合最上方的图来理解,当值为0时Systick的时钟频率为AHB/8也就是72MHz/8=9MHz,当值为1时Systick的时钟频率为AHB桥的频率。AHB桥的频率常用为72MHz。
COUNTFLAG该位的作用就是告诉使用者(芯片程序)Systick已经计数完成,用户程序可以通过检测该位是否为"1"来判断Systick的计数状态。
RELOAD该位是一个24位的寄存器,也就是说最大支持0xFFFFFF,同时还是能够自动重装载值,自动重装载的理解就是当RELOAD倒数至0后,能够重新将用户预设值填充,比如说预设值为0xFF,那么当倒数至0时,它能够自动将0xFF填充进RELOAD。
CURRENT该位是与RELOAD相对应的,它的值就等于RELOAD的值,只不过当我们对该寄存器进行写操作时,会强行将RELOAD的值清0,同时会将CTRL->COUNTFLAG的标志位置0。读操作则只是返回RELOAD的值。
6.2 代码
static uint8_t us = 0;
static uint16_t ms = 0;void SysTickConfig(void)
{SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);us = SystemCoreClock / 8000000;ms = (uint16_t )us *1000;
}void delay_us(uint32_t nus)
{uint32_t flags;SysTick->LOAD = nus * us;SysTick->VAL = 0x00;SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;do{flags = SysTick->CTRL;}while((flags&0x01)&&!(flags&(1<<16)));SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;SysTick->VAL = 0x00;
}void delay_ms(uint16_t nms)
{uint32_t flags;SysTick->LOAD = (uint32_t )nms * ms;SysTick->VAL = 0x00;SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;do{flags = SysTick->CTRL;}while((flags&0x01)&&!(flags&(1<<16)));SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;SysTick->VAL = 0x00;
}
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8)
配置CTRL->CLKSOURCE,将其选择为外部时钟源。
us = SystemCoreClock / 8000000
这里是整个Systick的重点,定时器准不准就看这里的参数,SystemCoreClock 是系统时钟频率,这里取72MHz,同时又由于上方代码进行了一个8分频,所以需要除以8。但如果单单只是/8,那么此时一个us应该为1s,而Systick的计数速度是由时钟频率决定的,此时时钟频率为9MHz,代表计数一秒需要数9M个数,而1s中有1M个us,所以用9M/1M就等于Systick计时1us需要数的数,完整的式子应该是 us = (72,000,000 / 8) / 1,000,000=9
ms = (uint16_t )us *1000
这里不难理解,1ms就是等于1000us,前面加个强制类型转换是为了让数据类型匹配上,避免编译器优化,造成数据丢失。
SysTick->LOAD = nus * us
此处就是给LOAD->RELOAD填充计数值自动重装载值,切记此处最大不超过24位。
SysTick->VAL = 0x00
这里是为了清空计数器,确保计数精准。
SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk
启动Systick。
do
{
flags = SysTick->CTRL;
}while((flags&0x01)&&!(flags&(1<<16)));
此处作用是等待计数完成,flags&(1<<16)这里就是检测计数完成COUNTFLAG标志位是否为'1'
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk
关闭Systick。
SysTick->VAL = 0x00
再次清空计数器。
下方的delay_ms()的原理同上方一样,只不过是将SysTick->LOAD = nus * us 的us换成ms,SysTick->LOAD = nms * ms ,当使用delay_ms()时,最大延时建议不超过1500ms
7 蓝牙模块
CH340模块(USB转TTL) HC-05模块
VCC(5V) —————————— VCC
GND —————————— GND
RXD —————————— TXD
TXD —————————— RXD
最开始,用USB转TTL连接HC-05模块(注意此时需要先按住HC-05模块上面的按钮再上电),这时会进入AT模式(此时的灯应该是间隔比较长时间才灭一次),然后打开串口调试助手,波特率设为38400,接下来进行初始化操作
按照步骤
配置蓝牙模块基本信息
AT+NAME=HC-05 修改蓝牙模块名称为HC-05
AT+ROLE=0 蓝牙模式为从模式
AT+CMODE=1 蓝牙连接模式为任意地址连接模式,也就是说 该模块可以被任意蓝牙设备连接
AT+PSWD=1234 蓝牙配对密码为1234
AT+UART=9600,0,0 蓝牙通信串口波特率为9600,停止位1位, 无校验位
我们直接把蓝牙模块插到原来USB转TTL的位置上(蓝牙模块的用处就是可以无线调试而不用电脑上的虚拟串口调试) (注意不要按按钮)
我们在手机上安装蓝牙串口调试软件,并配对(注意在这之前手机的设置->蓝牙里已经连接成功)
然后这时会发现灯处于长灭状态(偶尔亮一会),就可以正常使用了,我们在手机里输入数据,跟原来用电脑的虚拟串口一模一样
stm32攻略(随时更新,更新时间:2023.5.5)相关推荐
- 阿里巴巴大数据计算平台MaxCompute(原名ODPS)全套攻略(持续更新20171127)
概况介绍 大数据计算服务(MaxCompute,原名ODPS,产品地址:https://www.aliyun.com/product/odps)是一种快速.完全托管的TB/PB级数据仓库解决方案.Ma ...
- 【面试技巧】最全的面试求职攻略_每日更新
12.02更新~ ◣◤◣大家想看哪方面的更多?或者有什么关于职场的疑惑想要提问哒~都可以在这里留言或者给小白白发豆油~小白白都会去搜集整理编辑最终更新出来~ ◣◤◣如果觉得对大家有帮助,将继续更新~ ...
- 服务器维护必刷稀有宠物,诛仙手游稀有宠物捕捉攻略 稀有宠物刷新时间地点汇总...
诛仙手游稀有宠物捕捉攻略,稀有宠物刷新时间地点汇总.希望能够帮助大家早日入手自己喜欢的宠物,下面一起来看看攻略吧. 宠物的捕捉等级表 所谓冲级的优势在这里就体现出来了. 系统设置调到最佳位置 最重要的 ...
- cipher攻略(不断更新)
cipher是一个在线解谜.闯关.很烧脑细胞的游戏,适合于推理狂,数学Geek,各类变态玩家.在享受游戏的过程中,你还可以学习到:编解码,密码学,进制转换,图像处理,基础乐理,世界地理,各地习俗,历史 ...
- CentOS 5.5 安装配置全攻略 (无线上网 更新源 显卡驱动 firefox3.6 flash插件 编译boost1.43.0 雅黑字体...
unbuntu虽然很好,但用来开发并不是很好,很多东西库都比较新,在上面开发的东西兼容性和可移植性差,所以最终还是选择了centos5.4. centos安装后首先 解决上网的问题 安装好后,无法识别 ...
- 黑客丛林通关攻略参考(更新中)
黑客丛林之旅游戏链接地址:http://www.fj543.com/hack/ 1.提示语:在浏览器端用脚本进行身份验证是很容易被破解的. 查看源代码,密码在JS脚本中,典型的本地验证(在浏览器按F1 ...
- 小花仙攻略 各种花成熟时间和经验点
盆栽类 ·吊兰(成熟时间:6~12小时) 白色吊兰(没授粉)经验值1点 6~12小时/经验点 白色吊兰(授粉的)经验值2点 6~12小时/经验点 粉色吊兰(没授粉)经验值2点 3~6小时/经验点 粉色 ...
- 奶块1月25日服务器维护时间,奶块1月25更新公告 | 手游网游页游攻略大全
发布时间:2016-01-15 LOL8月25更新排位赛BUG是什么?LOL英雄联盟在8月25日的更新之后出现了排位赛的BUG,导致了可以晋级但是没有晋级.下面就是多游攻略带来的LOL8月25更新排位 ...
- 方舟linux服务器更新,方舟怎么更新服务器版本 | 手游网游页游攻略大全
发布时间:2016-06-01 pokemon go官方在2016年7月31日进行了一个重大的版本更新,新版本带给玩家太多的惊喜和刺激,但是老的玩家会感到微微的失落,毕竟很多格局已经被打破,你需要重新 ...
最新文章
- c# 字符串是否相等
- Cocos2d-x win7 + vs2010 配置图文详解 .
- 'putText' is not a member of 'cv'
- php 类 静态调用 实例化 效率,php类的静态调用和实例化调用有哪些不同点?
- mahout基于Hadoop的CF代码分析(转)
- 寻址(实模式和保护模式)
- 浅谈MD5加密算法中的加盐值(SALT)
- 图论--Floyd总结
- (pytorch-深度学习系列)卷积神经网络中的填充(padding)和步幅(stride)
- 原生语言开发web版万岳网校源码 v2.2.0
- 关于@SuppressWarnings(unchecked)注解
- ScrollView各属性,及代理方法汇总
- 怎样快速学习shell语言
- Vova and Train (codeforces 1066A)
- 23岁的Python,这些年在编程语言排行榜上直线上升的原因是什么?很多人都不解
- Ubuntu 16 NFS的安装与使用
- css04 float
- 项目使用jdk17人傻了
- IP与MAC绑定的难题
- java futuretask 单例_集群环境下java单例查询多了就异常
热门文章
- std::map与std::unordered_map
- 无法嵌入互操作类型“stdole.StdFontClass”的解决方法
- kafka manager安装和使用
- 《沟通的方法》笔记三:反向叙述
- Attributes.add
- 国际经济合作真题全集
- python使用清华源镜像安装包
- 福州市计算机等级考试培训点,计算机等级考试培训
- YII2 使用qiniu插件 上传多张图片回调显示
- shell编程(六) : [shell基础] 基本shell脚本