您的位置:首页 > 新闻 > 资讯 > 移动端是指手机还是电脑_今天汽油价格_保定百度seo公司_百度竞价推广屏蔽软件

移动端是指手机还是电脑_今天汽油价格_保定百度seo公司_百度竞价推广屏蔽软件

2025/1/11 22:38:56 来源:https://blog.csdn.net/qq_64219867/article/details/144884866  浏览:    关键词:移动端是指手机还是电脑_今天汽油价格_保定百度seo公司_百度竞价推广屏蔽软件
移动端是指手机还是电脑_今天汽油价格_保定百度seo公司_百度竞价推广屏蔽软件

需求描述

让MCU进入睡眠模式,然后通过串口发送消息来唤醒MCU退出睡眠模式。观察LED在进入休眠模式后是否仍然开启。

思考

首先睡眠模式,唤醒的条件是中断,外部内部都可以,这里的串口接收中断时内部中断。

拓展:中断分为三大类:内核中断也叫异常,片上外设中断对于stem32来说也是内部所以叫内部中断,片外外设的中断stem32外部的中断,叫外部中断

图解:

软件设计:

设计到的寄存器:

ARM内核:

代码:

    /* 1. 设置普通睡眠模式 */SCB->SCR &= ~SCB_SCR_SLEEPDEEP;

usart.h

#ifndef __USART_H
#define __USART_H#include "stm32f10x.h"
#include <stdio.h>// 初始化
void USART_Init(void);// 发送一个字符
void USART_SendChar(uint8_t ch);// 接收一个字符
uint8_t USART_ReceiveChar(void);// 发送字符串
void USART_SendString(uint8_t * str, uint8_t size);// 接收字符串
void USART_ReceiveString(uint8_t buffer[], uint8_t *size);#endif

usart.c

之前的代码新增3.4和4以及中断服务程序。

#include "usart.h"// 初始化
void USART_Init(void)
{// 1. 开启时钟RCC->APB2ENR |= RCC_APB2ENR_USART1EN;RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;// 2. GPIO 工作模式// 2.1 PA9 - TX,复用推挽输出,CNF = 10,MODE = 11GPIOA->CRH |= GPIO_CRH_MODE9;GPIOA->CRH |= GPIO_CRH_CNF9_1;GPIOA->CRH &= ~GPIO_CRH_CNF9_0;// 2.2 PA10 - RX,浮空输入,CNF = 01,MODE = 00GPIOA->CRH &= ~GPIO_CRH_MODE10;GPIOA->CRH &= ~GPIO_CRH_CNF10_1;GPIOA->CRH |= GPIO_CRH_CNF10_0;// 3. 串口模块配置// 3.1 设置波特率 115200USART1->BRR = 0x271;// 3.2 使能串口和收发模块USART1->CR1 |= USART_CR1_UE;USART1->CR1 |= (USART_CR1_TE | USART_CR1_RE);// 3.3 配置数据帧的格式USART1->CR1 &= ~USART_CR1_M;    // 长度为 8 位USART1->CR1 &= ~USART_CR1_PCE;  // 不使用校验位USART1->CR2 &= ~USART_CR2_STOP; // 1 位停止位// 3.4 开启串口接收中断USART1->CR1 |= USART_CR1_RXNEIE;// 4. NVIC配置NVIC_SetPriorityGrouping(3);NVIC_SetPriority(USART1_IRQn, 3);NVIC_EnableIRQ(USART1_IRQn);
}// 发送一个字符
void USART_SendChar(uint8_t ch)
{// 判断 TDR 是否为空,必须等待 TDR 为空才能继续发送while ((USART1->SR & USART_SR_TXE) == 0){}// 将要发送的数据写入TDRUSART1->DR = ch;
}// 接收一个字符
uint8_t USART_ReceiveChar(void)
{// 判断 RDR 是否非空,必须等待 RDR 有数据才能读取出来while ((USART1->SR & USART_SR_RXNE) == 0){}// 读取接收到的数据,返回return USART1->DR;
}// 发送字符串
void USART_SendString(uint8_t *str, uint8_t size)
{for (uint8_t i = 0; i < size; i++){USART_SendChar(str[i]);}
}// 接收字符串
void USART_ReceiveString(uint8_t buffer[], uint8_t *size)
{// 定义变量,保存当前接收到的字符个数uint8_t i = 0;// 不停地接收字符,直到检测到空闲帧// 错误写法:// while ( (USART1->SR & USART_SR_IDLE) == 0 )// {// 	buffer[i] = USART_ReceiveChar();// 	i++;// }// 正确写法:// 外层循环:不停读取下一个字符while (1){// 内层循环:判断当前数据帧是否结束while ((USART1->SR & USART_SR_RXNE) == 0){// 一旦已经检测到空闲帧,就立刻退出if (USART1->SR & USART_SR_IDLE){*size = i;USART1->DR;return;}}buffer[i] = USART1->DR;i++;}
}// 重写fputc函数
int fputc(int ch, FILE * file)
{USART_SendChar(ch);return ch;
}// 中断服务程序
void USART1_IRQHandler(void)
{if (USART1->SR & USART_SR_RXNE){// 读取接收到的数据,清除标志位uint8_t c = USART1->DR & 0xff;USART_SendChar(c);}
}

main.c

前面有__的命令,证明时底层的命令,汇编指令。

#include "usart.h"
#include "delay.h"
#include "led.h"void enter_sleep_mode(void);int main(void)
{// 初始化USART_Init();LED_Init();printf("低功率实验:睡眠模式...\n");// 1. 开启LED灯,延时2s,模拟正常程序执行过程LED_On(LED_1);Delay_s(2);while (1){// 2. 进入睡眠模式printf("正常代码执行完毕,3s后进入睡眠模式...\n");Delay_s(3);printf("进入睡眠模式");enter_sleep_mode();// 3. 以下代码只有在唤醒之后才会执行printf("从睡眠模式中唤醒...\n");Delay_s(2);}
}// 定义进入睡眠模式的函数
void enter_sleep_mode(void)
{// 1. 设置普通睡眠模式(默认)SCB->SCR &= ~SCB_SCR_SLEEPDEEP;// 2. 使用WFI指令,进入睡眠模式__WFI();
}

led.h

#ifndef __LED_H
#define __LED_H#include "stm32f10x.h"// 宏定义LED灯
#define LED_1 GPIO_ODR_ODR0
#define LED_2 GPIO_ODR_ODR1
#define LED_3 GPIO_ODR_ODR8// 初始化
void LED_Init(void);// 开关LED灯
void LED_On(uint16_t led);
void LED_Off(uint16_t led);// 翻转LED灯状态
void LED_Toggle(uint16_t led);// 控制所有LED灯的开关
void LED_OnAll(uint16_t leds[], uint8_t size);
void LED_OffAll(uint16_t leds[], uint8_t size);#endif

led.c

#include "led.h"// 初始化
void LED_Init(void)
{// 1. 时钟配置,打开GPIOA时钟RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;// 2. 工作模式配置,PA0、PA1、PA8 通用推挽输出,CNF = 00,MODE = 11GPIOA->CRL |= GPIO_CRL_MODE0;GPIOA->CRL &= ~GPIO_CRL_CNF0;GPIOA->CRL |= GPIO_CRL_MODE1;GPIOA->CRL &= ~GPIO_CRL_CNF1;GPIOA->CRH |= GPIO_CRH_MODE8;GPIOA->CRH &= ~GPIO_CRH_CNF8;// 3. 初始状态所有引脚输出高电平,关灯LED_Off(LED_1);LED_Off(LED_2);LED_Off(LED_3);
}// 开关LED灯
void LED_On(uint16_t led)
{GPIOA->ODR &= ~led;
}
void LED_Off(uint16_t led)
{GPIOA->ODR |= led;
}// 翻转LED灯状态
void LED_Toggle(uint16_t led)
{// 根据IDR对应位的值,判断当前LED状态if ((GPIOA->IDR & led) == 0){LED_Off(led);}else{LED_On(led);}
}// 控制所有LED灯的开关
void LED_OnAll(uint16_t leds[], uint8_t size)
{for (uint8_t i = 0; i < size; i++){LED_On(leds[i]);}
}
void LED_OffAll(uint16_t leds[], uint8_t size)
{for (uint8_t i = 0; i < size; i++){LED_Off(leds[i]);}
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com