项目需求,无线通信+低功耗
一、STM32CUBEMX配置LL库函数LPUSART
1、LPUSART基本配置
2、LPUSART中断使能
串口中断优先级可以简单粗暴的(不是懒)设为最高0。如下
3、LPUSART-生成代码
void MX_LPUART1_UART_Init(void)
{
LL_LPUART_InitTypeDef LPUART_InitStruct = {0};
LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
/* Peripheral clock enable */
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_LPUART1);
LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_GPIOC);
/**LPUART1 GPIO Configuration
PC10 ------> LPUART1_TX
PC11 ------> LPUART1_RX
*/
GPIO_InitStruct.Pin = LL_GPIO_PIN_10;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
GPIO_InitStruct.Alternate = LL_GPIO_AF_0;
LL_GPIO_Init(GPIOC, &GPIO_InitStruct);
GPIO_InitStruct.Pin = LL_GPIO_PIN_11;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
GPIO_InitStruct.Alternate = LL_GPIO_AF_0;
LL_GPIO_Init(GPIOC, &GPIO_InitStruct);
/* LPUART1 interrupt Init */
NVIC_SetPriority(RNG_LPUART1_IRQn, 0);
NVIC_EnableIRQ(RNG_LPUART1_IRQn);
LPUART_InitStruct.BaudRate = 256000;
LPUART_InitStruct.DataWidth = LL_LPUART_DATAWIDTH_8B;
LPUART_InitStruct.StopBits = LL_LPUART_STOPBITS_1;
LPUART_InitStruct.Parity = LL_LPUART_PARITY_NONE;
LPUART_InitStruct.TransferDirection = LL_LPUART_DIRECTION_TX_RX;
LPUART_InitStruct.HardwareFlowControl = LL_LPUART_HWCONTROL_NONE;
LL_LPUART_Init(LPUART1, &LPUART_InitStruct);
}
4、LPUSART用户添加代码
除了调用生成的初始化函数,还需以下操作
LL_LPUART_EnableIT_RXNE(LPUART1); //启用 检测到接收非空 中断
LL_LPUART_EnableIT_IDLE(LPUART1); //启用 检测到空闲 中断
//使能LPUART1
LL_LPUART_Enable(LPUART1);
//查询LPUART1初始化
while(!(LL_LPUART_IsActiveFlag_TEACK(LPUART1))||(!(LL_LPUART_IsActiveFlag_REACK(LPUART1))))
{}
二、蓝牙引脚定义
1、将SEL1与SEL0接地/拉低,以选择串口通信模式
2、CUBEMX引脚初始化
(打糊的)引脚对应真正使用的原理图
User Label项是用户为引脚设置的名称,会在main.h生成相应的宏定义(这功能真令人舒适)。如下(只是例子)
3、GPIO-生成代码
/*Configure GPIO pin : PtPin */
GPIO_InitStruct.Pin = BleINT_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(BleINT_GPIO_Port, &GPIO_InitStruct);
/*Configure GPIO pins : PBPin PBPin */
GPIO_InitStruct.Pin = BleWakeup_Pin|BleRST_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/*Configure GPIO pin : PtPin */
GPIO_InitStruct.Pin = BleState_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(BleState_GPIO_Port, &GPIO_InitStruct);
/*Configure GPIO pin : PtPin */
GPIO_InitStruct.Pin = BleCtrl_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(BleCtrl_GPIO_Port, &GPIO_InitStruct);
三、LPUSART发送字符串函数
接下来,单片机与蓝牙的通信全仰仗这个函数啦
//串口LPUART1发送字符串
void LpuartSendBuf(unsigned char* buf,unsigned char len)
{
unsigned char i;
for(i=0;i<len;i++) /* 循环直到发送结束 */
{
LL_LPUART_TransmitData8(LPUART1, (uint8_t)buf[i]);
// while(!LL_LPUART_IsActiveFlag_TXE(LPUART1)) {} //1:数据传输到移位寄存器 (当发送数据寄存器(LPUART_TDR)的内容已传输到移位寄存器时)
while(!LL_LPUART_IsActiveFlag_TC(LPUART1)) {} //1:传送已完成(如果已完成对包含数据的帧的发送并且TXE置1)
}
}
四、LPUSART中断处理(收/发数据)函数
uint8_t ReceiveData=0; //数据处理
uint8_t p_LPUart_Rx=0;
uint8_t LPUart_Buffer[35]={0}; //串口接收缓冲
void RNG_LPUART1_IRQHandler(void) //全局中断
{
if(LL_LPUART_IsActiveFlag_RXNE(LPUART1)) //==1:已准备好读取接收到的数据
{
LPUart_Buffer[p_LPUart_Rx]=LL_LPUART_ReceiveData8(LPUART1); //接收数据并自动清RXNE标志位
p_LPUart_Rx++;
}
if(LL_LPUART_IsActiveFlag_IDLE(LPUART1)) //==1:检测到空闲线路
{
LL_LPUART_ClearFlag_IDLE(LPUART1); //清除检测到空闲线路标志位
p_LPUart_Rx=0;
//数据处理
//注:蓝牙主从机通信实验:互发数组,有3个uint8_t类型的元素
//uint8_t Send[3]={0xAA,0x01,0xBB};
if(LPUart_Buffer[0]==0xAA) //判断帧头
{
if(LPUart_Buffer[2]==0xBB) //判断帧尾
{
ReceiveData=LPUart_Buffer[1]; //接收数据
}
}
}
}
//清空缓冲区
void clean_rebuff(void)
{
uint16_t i = 36;
while(i)
LPUart_Buffer[--i]=0;
}
五、蓝牙-单片机通信
1、此蓝牙的通信基于CC2640 R2透传规格书,在我上传的资源中有原版(当然是中文啦)。
单片机向蓝牙写数据 时序:
2、测试程序
单片机与蓝牙的命令通信均采用AT指令。指令执行成功,蓝牙会给单片机回应以"AT+OK"为开头的字符串。
#define WAKEUP_CRL() LL_GPIO_ResetOutputPin(BleWakeup_GPIO_Port, BleWakeup_Pin);
#define WAKEUP_SET() LL_GPIO_SetOutputPin(BleWakeup_GPIO_Port, BleWakeup_Pin);
#define RST_CRL() LL_GPIO_ResetOutputPin(BleRST_GPIO_Port, BleRST_Pin);
#define RST_SET() LL_GPIO_SetOutputPin(BleRST_GPIO_Port, BleRST_Pin);
//简简单单的 测试函数
u8 blue (void)
{
WAKEUP_CRL();
LL_mDelay(1);
//注:蓝牙会将被写入的数据发送出去。
BLE_LpUartWrite((u8*)"AT\r\n",strlen("AT\r\n"));
LL_mDelay(100);
WAKEUP_SET();
LL_mDelay(1);
//AT+OK
if(LPUart_Buffer[3]==0x4F) //0x4F对应"O"
{
if(LPUart_Buffer[4]==0x4B) //0x4B对应"K"
{
clean_rebuff();
return 1;
}
}
else
{
clean_rebuff();
return 0;
}
}
灵活运用:按照测试函数的时序来即可,对照透传书更换相应AT指令即可。
六、蓝牙主机-蓝牙从机通信
BleState=1,模块处于断开状态,BleState=0模块处于连接状态。
单片机读(蓝牙接收到的)数据 时序:
接下来看接收数据流程图:
程序(包括接收和发送):
uint8_t Send[3]={0xAA,0x01,0xBB};
void BLE_LpUartWrite(unsigned char *str,unsigned char len)
{
LpuartSendBuf(str,len);
}
while(1)
{
if(!LL_GPIO_IsInputPinSet(BleState_GPIO_Port,BleState_Pin)) //蓝牙已连接
{
if(!LL_GPIO_IsInputPinSet(BleINT_GPIO_Port,BleINT_Pin)) //有数据到来
{
WAKEUP_CRL(); //接收数据
}
if(sendtime>=3) //3s 每3秒发送一次数据
{
BLE_LpUartWrite(Send,3);//发送数据
clean_rebuff();
sendtime=0; //重置:发送数据计时
}
relinktimestop_clear=0;
}
else //蓝牙未连接
{
if(relinktime>=3) //3s
{
clean_rebuff();
blue_sca_link_mac(); //指定从机MAC地址连接
LL_mDelay(100);
relinktime=0; //重置:重连计时
}
}
}
七、完了
内容太多,先就这了,差不多了