嵌入式系统开发(STM32)复习笔记

模拟习题为主。考60分简答题,40分编程加程序设计题。以下习题答案为自己做的,并非参考答案,如有错误,还请指正!

简答题

  1. CM3内核寄存器包含R0-R15,这些寄存器的字长是多少?说明各个寄存器的用途
    答:
    R0-R7是低组寄存器,所有指令都能访问;
    R8-R12是高组寄存器,16位指令不能访问,32位指令不受限制;
    R0-R12字长全为32位;
    R13是堆栈指针;
    R14是链接寄存器;
    R15是程序计数器

  2. 什么是嵌入式系统?嵌入式系统一般由哪几部分构成?
    答:(1)是一种嵌入受控器件内部,为特定应用而设计的专用计算机系统,具有“嵌入性”、“专用性”和“计算机系统”3个基本要素。(以应用为中心,以现代计算机技术为基础,能够根据用户需求(功能、可靠性、成本、体积、功耗、环境等)灵活裁剪软硬件模块的专用计算机系统。)
    (2)它一般由嵌入式微处理器、外围硬件设备、嵌入式操作系统以及用户的应用程序等四个部分组成。
    嵌入式系统通常执行的是带有特定要求的预先定义的任务,强调控制能力与控制的可靠性;
    而通用计算机则可以通过安装各种软件执行各种不同的任务,强调高速、海量的数值计算。

  3. 简述普林斯顿结构和哈佛结构分别的含义是什么,本次实验处理器属于哪一种?
    答:普林斯顿结构是一种将程序指令存储器和数据存储器合并在一起的存储器结构;
    哈佛结构是一种将程序指令和数据存储分开的存储器结构;
    STM32属于哈佛结构。

  4. 阐述嵌入式系统定义中的4个基本要点?
    答: 1.应用中心的特点; 2.计算机系统的特点; 3.软硬件可裁剪的特点; 4.专用性的特点。

  5. 嵌入式系统内核种类有哪些,各自的特点?/简述MCU、MPU及DSP三种嵌入式内核的特点
    答:
    (1)嵌入式微处理器(MPU):对实时多任务有很强的支持能力;具有很强的存储区保护功能;具有可扩展能力;但是要配备ROM,RAM,总线接口以及各种外设接口等;
    (2)微控制器(MCU):单片化,体积小,功耗和成本低,可靠性高;但是处理速度有限,进行复杂应用很困难;
    (3)数字信号处理器(DSP):在信号处理方法优势很大;但是不适合运行操作系统。

  6. 嵌入式C语言中static、volatile, const的作用是什么?举例说明
    答:
    Static用在函数前或全局变量前,可以隐藏该函数或变量的跨文件可见性,加了static,就会对其他源文件隐藏; Static用在局部变量前,可以让局部变量持久化,即函数结束后该变量的值仍然不变,直到程序运行结束以后才释放;不想被释放的时候,可以使用static修饰;考虑到数据安全性可以使用static修饰!
    volatile的作用是作为指令关键字,确保本条指令不会因编译器的优化而省略,且要求每次直接读值,
    以下场合应使用volatile
    1、中断服务函数中修改的供其它程序检测的变量需要加volatile;
    2、多任务环境下各任务间共享的标志应该加volatile;
    3、存储器映射的硬件寄存器通常也要加volatile说明,因为每次对它的读写都可能有不同意义;
    Const关键字在嵌入式中主要有以下作用
    (1)欲阻止一个变量被改变,可以使用const关键字。在定义该const变量时,通常需要对它进行初始化,因为以后就没有机会再去改变它了;
    (2)对指针来说,可以指定指针本身为const,也可以指定指针所指的数据为const,或二者同时指定为const;
    (3)在一个函数声明中,const可以修饰形参,表明它是一个输入参数,在函数内部不能改变其值;

  7. 基于CMSIS标准的软件架构分为那几层?其中的CMSIS层一般由哪几部分组成?
    答:(1)用户应用层,操作系统层,CMSIS层,硬件寄存器层;
    (2)CMSIS层由核内外设访问层,片上外设访问层,外设访问函数组成.

  8. 简述STM32串行通信数据帧特点,举例至少三种嵌入式系统常见的串行接口,并描述其特点。
    答:(1)Stm32的串口通信是按数据帧为单位进行收发通信的,一个数据帧通常包含起始位、数据位、校验位,通常配置为8N1,即8个数据位,1个起始位,不使用校验位。
    常用的串行接口包括SPI、I2C、RS485,UART, CAB总线,USB接口。
    RS485,常用于多机通信,传输距离远,速度一般,属于半双工通信,即同一时刻只能单向。
    SPI :是一种高速通信总线,支持多机通信,传输距离短,常用在电路板上的不同设备之间。
    I2C:也是一种多节点串行通信方式,速度较低,常用于传感器接口,有SDA数据线,SCL时钟线两根信号线。

  9. 简述基于cubeIDE进行STM32程序开发的流程,开发中遇到bug如何排查?
    答:
    开发流程:
    (1) 新建项目; (2)配置芯片资源并生成初始化代码; (3)代码编写与调试; (4)生成给芯片烧录用的文件; (5)烧录程序到目标芯片
    bug调试:
    1.在CUBEMX中配置SYS->Debug:
    2.debug调试设置:菜单栏“Run->Debug Configurations”,弹出设置框,进入调试设置
    3.设置Debug As目标为“STM32 MCU C/C++ Application”,进入调试
    4.调试观察变量或表达式的值
    使用可以参看以下链接:
    STM32CubeIDE使用,基础说明与开发流程

  10. STM32的GPIO的配置模式有那几种?如何选择?如何进行配置模式的配置?
    1.四种输入模式:
    上拉输入(GPIO_Mode_IPU):在默认状态下,读取的GPIO引脚为高电平
    下拉输入(GPIO_Mode_IPD):在默认状态下,读取的GPIO引脚为低电平
    浮空输入(GPIO_Mode_IN_FLOATING):配置成这种模式时,电压表测量引脚电压为1点几伏,为不确定值,因为其阻抗较大,所以一般作为IIC,USART的输入管脚应用
    模拟输入(GPIO_Mode_AIN):在使用ADC外设的时候,将管脚配置成此模式,这样 外部模拟信号直接进入MCU
    2.四种输出模式:
    推挽输出(GPIO_Mode_Out_PP):一般在连接这个管脚的电平在0到3.3V的时候,配置成此模式。
    开漏输出(GPIO_Mode_Out_OD):在连接这个管脚的电平在5V左右时,配置成此模式,在配置成这个模式时,管脚外部一定要连接上拉电阻。
    复用开漏输出(GPIO_Mode_AF_OD)
    复用推挽输出(GPIO_Mode_AF_PP)

这里写的比较笼统,没总结好,可以参看这篇文章!
GPIO 口的输入,输出模式及其说明

  1. 简述嵌套向量中断控制器(NVIC)的主要特性。
    答:
    NVIC:提供中断控制器,用于总体管理异常;
    有以下特性:支持嵌套和向量中断;自动保存和恢复处理器状态;动态改变优先级;简化和确定中断时间。

  2. 简述NVIC中的两种优先级机制及配置方式。
    答:抢占优先级和响应优先级;配置方式:系统运行后先设置中断优先级分组(整个系统执行过程中,只设置一次中断分组);针对每个中断,设置对应的抢占优先级和响应优先级

  3. 中断和异常有什么区别,共支持多少中断和异常?简述使用库函数进行EXTI中断程序设计的基本步骤。
    答:中断来自内核外部,异常来自内核内部,它们都会打断正常的程序运行; ARM cortex_m3 内核支持 256 个中断(16 个内核+240 外部),STM32支持15个异常和68个中断
    使用库函数开发时:

  1. 打开时钟,配置GPIO口
  2. 配置NVIC,其中包括初始化两种优先级,优先级分组
  3. 配置EXTI,其中包括GPIO口和EXTI的映射关系,EXTI触发条件
  4. 编写中断服务函数
  1. 什么是stm32的占先优先级?什么是副优先级?在此基础上stm32的中断嵌套规则是什么?
    答:
    占先优先级:高占先式优先级的中断事件会打断当前的主程序/中断程序运行—抢断式优先响应,俗称中断嵌套。
    副优先级:在占先式优先级相同的情况下,高副优先级的中断优先被响应(数值越小表明副优先级越高)。
    规则:高抢占优先级可以打断低抢占优先级的中断,从而实现中断嵌套。若两个中断的抢占优先级相同,不可发生嵌套,其中副优先级高的(数值更低)先执行。

  2. 如何设置STM32的串口的波特率(串口传输的波特率即为每秒钟传输二进制的位数)
    通过USART_BRR寄存器来设置,计算波特率公式如下:如何设置STM32的串口的波特率。
    波特率计算
    fck是给外设的时钟;USARTDIV是一个无符号的定点数,表示对串口的时钟源fck进行分频,16表示的正是1bit数据的采样次数。

  3. 简述使用库函数对GPIO口编程的基本步骤。
    答:
    1.使用GPIO_Configuration定义结构体变量GPIO_InitStructure;该结构体有三个变量GPIO_Pin(GPIO设备引脚),GPIO_Speed(GPIO设备速率),GPIO_Mode(GPIO设备工作模式);

//GPIO口设置
void GPIO_Configuration(void)
{
//声明结构体
  GPIO_InitTypeDefGPIO_InitStructure;
//设置选择引脚
 GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9;
//设置引脚最大输出频率
 GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
//设置引脚输出模式
 GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
根据设置的InitStructure 初始化GPIO口
 GPIO_Init(GPIOC,&GPIO_InitStructure);
}

2.调用GPIO_Init函数初始化;

//GPIO_InitTypeDef在stm32f10x_gpio.h中如下定义:
typedef struct
{
      u16 GPIO_Pin;
      GPIO_Speed_TypeDef GPIO_Speed;
      GPIO_Mode_TypeDef GPIO_Mode;
} GPIO_InitTypeDef

3.库首先将各个设备所有寄存器的配置字进行预先定义,然后封装在结构或枚举变量中,当用户调用对应的库函数时,会根据用户传入的参数从这些封装好的结构或者枚举变量中取出对应的配置字,最后写入寄存器中,完成对底层寄存器的配置.

  1. 嵌入式C语言编程中,列出至少三种位运算符,说明它们的作用.
    答:(1)“按位与”运算符 & :将源操作数某些位置0,其它位不变;
    (2)“按位或”运算符 | :将源操作数某些位置1,其它位不变;
    (3)“按位异或”运算符 ^ :进行位翻转;
    (4)“按位取反”运算符 ~ :按位进行取反;
    (5)左移运算符<<;
    (6)右移运算符>>。

  2. 简述工程项目开发主要环节,其中软件设计环节的主要方法有哪些?
    答:体系结构设计、用户界面设计、数据库设计、模块设计、数据结构和算法设计。

  3. 状态图设计的优点和缺点各是什么,如何用程序实现?
    答:优点:1.简化对类的设计的确认2.详细说明了由时间序列引起的状态序列3.清晰地描述了状态转换时所必需的触发事件、监护条件和动作等影响转换的因素,有利于程序员避免程序中非法事件的进入;
    缺点:主要着重于对象的状态及其状态之间的转换,没有注重描述行为的动作。

  4. GPIO口的模式有哪几种,任选其中三种,举例说明该模式的用途。
    答:8种
    1.GPIO_Mode_AIN模拟输入:ADC采集时使用该模式
    2.GPIO_Mode_IN_FLOATING浮空输入:连接到外部输入设备,如传感器等,使用该模式
    3.GPIO_Mode_IPD下拉输入:外部没有下拉,需要处理器内部下拉时
    4.GPIO_Mode_IPU上拉输入:外部没有上拉,需要处理器内部上拉时
    5.GPIO_Mode_Out_OD开漏输出:开漏输出可以实现多门的线与逻辑关系外,还可以用于直接驱动较大电流的负载,如继电器、脉冲变压器、指示灯等
    6.GPIO_Mode_Out_PP推挽输出:推挽输出既可以输出低电平,也可以输出高电平,其优点是可以直接驱动功耗不大的数字器件,其结构一般是指两个三极管分别受两互补信号的控制,即工作的状态总处于一个导通,另一个截止的状态,两个对称的开关管每次只有一个导通,所以开关损耗小,效率高
    7.GPIO_Mode_AF_OD复用开漏输出
    8.GPIO_Mode_AF_PP复用推挽输出
    最后两种情况,GPIO口被用作第二功能时的配置情况(即并非作为通用IO口使用)。

  5. 什么是DMA,简述DMA控制器的基本功能,进行一次DMA传送,需要配置哪些参数?
    答:DMA(Direct Memory Access):直接存储器访问,完全用硬件执行I/O交换。
    功能:
    1.DMAC同外设之间有一对联络信号线——外设的DMA请求信号DREQ以及 DMAC向外设发出的DMA响应信号DACK;
    2.DMAC在接收到DREQ后,同CPU之间也有一对联络信号线——DMAC向CPU 发出总线请求信号(HOLD或BUSRQ),CPU在当前总线周期结束后向DMAC发出总线响应信号(HLDA或BUSAK),DMAC接管对总线的控制权,进入DMA操作方式;
    3.能发出地址信息,对存储器寻址,并修改地址指针。
    4.能决定传送的字节数,并能判断DMA传送是否结束。
    5.能发出DMA结束信号,释放总线,使CPU恢复总线控制权;
    6.能发出读、写控制信号,包括存储器访问信号和I/O访问信号。
    配置参数:确定数据每次传输的量,源地址和目标地址数据宽度的参数配置,配置源和目标数据指针的增量模式。

  6. 工程项目开发时,需要考虑哪些环节,各个环节分别完成哪些工作?
    答:工程开发时主要包含以下环节:
    市场调研:调研市场情况,分析市场趋势,市场需求;
    产品定义:市场开发人员根据市场调研情况,提出我们能够设计或提供什么产品来满足市场需求;
    需求:写出产品的需求说明书,定义出产品必须具备和可以具备的各项具体功能;
    总体设计:软件和硬件的总体结构图,包含哪些模块,模块之间的关系;
    详细设计:软件和硬件的详细设计,软件的算法、流程、硬件的连接逻辑;
    系统实现:软件代码编程、硬件电路板设计、装焊、调试;
    测试:模块功能测试、集成测试;
    验证和测试:进一步验证产品是否符合设计要求,是否满足用户需求;
    产品后期支持:版本控制、代码文档.

  7. 使用嵌入式技术实现一套钻井井场无线数据监控系统,包括底层节点、电池供电模块、传感器模块、无线通信模块、网关、数据存储和表示等部分,设计并阐述该系统的实现方案。

编程题

  1. 使用C语言完成以下功能,定义32位变量a,设置a的bit[19:18]位为1,清除a的bit[21]位为0(不改变其他位)。
uint32_t a;
a |= (0x03<<18);
a &=~(0x01<<21);
  1. 实现一个C函数,该函数能清除一个32位寄存器的指定位,不改变其他位。
void ClearReg(uint32_t* preg, uint8_t bit)
{
	If (bit >= 32)
		Return 255;
	*preg &= ~(0x01<<bit);
		Return 0
	}
  1. 实现一个C函数,该函数能设置一个32位寄存器的指定位,不改变其他位。
void ClearReg(uint32_t* preg, uint8_t bit)
{
	If (bit >= 32)
		Return 255;
	*preg |=(0x01<<bit);
		Return 0
	}
  1. 实现一个C函数,该函数能翻转一个32位寄存器的指定位,不改变其他位。
void ClearReg(uint32_t* preg, uint8_t bit)
{
	If (bit >= 32)
		Return 255;
	*preg ^=(0x01<<bit);
		Return 0
	}
  1. 在存储器地址为0x3000的地址单元开始处,依次存放着一个int类型变量和一个char类型变量,编写程序修改int类型变量的大小为0x12345678,修改char类型变量的大小为0xff.(这道题不是很确定)
#define Start_Address 0x3000
#define int (Start_Address+0x12345678)
#define char (int+0xff)
  1. 编写C语言程序,以字节(或以32位)为单位,将存储器中0x2000 0000单元处的2KB数据,复制到0x2000 3000地址单元处.
Unsigned char *src;
Unsigned char *des;
src = (Unsigned char *)0x2000 0000;
des = (Unsigned char *)0x2000 3000;
for(I = 0 ;i<2*1024;i++)
{
	*des = *src;
	Des++;
	Src++;
}
  1. 台灯有四种模式:低、中、高、熄灭,两个控制开关,开关1用于对四种工作模式进行循环切换,开关2用于控制是否进入睡眠模式,假设这两个开关均连接到处理器GPIO口,并配置为输入中断,
    a)用状态图设计该台灯的控制逻辑
    根据设计的状态图,设计实现下表两个GPIO口的中断处理ISR及main函数,可自主定义各类局部变量、全局变量。
    状态图
uint32_t sw1_pressed = 0, sw2_pressed = 0;
enum currstate = {stop, slow, normal, fast}
void switch1_isr()
{
	sw1_pressed = 1;
	
}
void switch2_isr()
{
	sw2_pressed = 1;
}
Int main()
{
	LightStop();
	currstate = stop;
	while(1){
		switch(currstate){
		case stop:
			LightStop ();
			if(sw1_pressed == 1){	
				sw1_pressed = 0;
				currstate = slow;
			}
		case slow:
			LightStart(slow)
			if(sw1_pressed == 1){
				sw1_pressed = 0;
				currstate = normal;
			}
			if(sw2_pressed == 1){
				sw2_pressed = 0;
				sleep_mode();
			}
		case normal:
				LightStart (normal)
				if(sw1_pressed == 1){
					sw1_pressed = 0;
					currstate = fast;
				}
				if(sw2_pressed == 1){
					sw2_pressed = 0;
					sleep_mode();
				}		
		case fast:
				LightStart(fast)
				if(sw1_pressed == 1){
					sw1_pressed = 0;
					currstate = fast;
				}
				if(sw2_pressed == 1){
					sw2_pressed = 0;
					sleep_mode ();
				}
		}
	}
}
  1. 实现一款医用注射泵,用文字的形式,完成产品的硬件结构设计、软件结构设计
  2. PM2.5,PM10空气质量传感器串口输出数据格式如表所示,按以下要求编写程序

在这里插入图片描述
答:这道题和下面实验第三题实际上是很类似的,只是一个是使用串口软件发送数据 ,这里是接收传感器数据。本质上差不多,主要是中间需要进行一个简单的数据处理,不过也很简单,没有涉及到移位等操作,按照公式直接写即可。


void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) 
{
	uint8_t checksum = 0;//校验和
	if(HAL_UART_Receive_IT(&huart2, aRxbuf, 8) == HAL_OK)  //接收中断
	{
		checksum = aRxbuf[2] + aRxbuf[3] + aRxbuf[4] + aRxbuf[5];//校验和
		if(checksum == aRxbuf[6])//证明接收到的数据是正确的
			PM25Data = (aRxbuf[3] * 256 + aRxbuf[2]) / (float)10;	
			PM10Data = (aRxbuf[5] * 256 + aRxbuf[4]) / (float)10;			
	} 
	printf("PM2.5浓度为:%0.3f ug/m3\r\n",PM25Data);
	printf("PM10 浓度为:%0.3f ug/m3\r\n",PM10Data);
} 
  1. 为汽车定速巡航功能进行fsm状态图建模,并用程序实现,各类接口函数可自主定义。
    在这里插入图片描述
    在这里插入图片描述
enum currstate = {cruiseDisable, cruiseEnable, cruiseStart}

main()
{
currstate = cruiseDisable;
}
SW_cruiseONOFF_callback()
{
	switch(currstate)
	case cruiseDisable:
		currstate = cruiseEnable;
	case cruiseEnable:
		currstate = cruiseDisable;
}
SW_cruiseSET_callback()
{
	switch(currstate)
	case cruiseDisable:
		break;
	case cruiseEnable:
		if( getCurrentSpeed()>30)
{
	cruiseStart(getCurrentSpeed());
	currstate = cruiseStart;
}

}
  1. 实现石油钻井井场数据采集,要求电池供电、无线通信、数据可上传云端、可同步到手机端,完成项目的硬件结构设计、软件结构设计

三次实验

  1. 按键控制小灯
//阻塞方式
if(HAL_GPIO_ReadPin(KEY_GPIO_Port, KEY_Pin) == 0){
	HAL_Delay(30);    //(防抖)
	if(HAL_GPIO_ReadPin(KEY_GPIO_Port, KEY_Pin) == 0){
		HAL_GPIO_TogglePin(LED2_RED_GPIO_Port, LED2_RED_Pin);
		while(HAL_GPIO_ReadPin(KEY_GPIO_Port, KEY_Pin) == 0);   //松手检测
 	}
}
HAL_Delay(1000);
//中断方式,这里不是单纯点灯,是通过按键改变灯的闪烁频率,即按键控制不同快慢的走马灯
//在最前面的这里初始化全局变量
/* USER CODE BEGIN PV */
int blinksign = 1;
/* USER CODE END PV */

//再修改中断函数
/* USER CODE BEGIN 4 */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
  if (blinksign == 1)
  {
	  blinksign = 0;
  }
  else
	  blinksign = 1;

}
/* USER CODE END 4 */

//最后写主函数
while(1){
	if (blinksign == 1)
	{
		HAL_GPIO_TogglePin(LED3_BLUE_GPIO_Port, LED3_BLUE_Pin);
		HAL_Delay(300);
	}
	else
	{
		HAL_GPIO_TogglePin(LED3_BLUE_GPIO_Port, LED3_BLUE_Pin);
		HAL_Delay(1500);
	}
}
  1. 把PB5端口配置为TIM3的channel2,PWM输出,配置TIM3模块和PWM模块,输出不同占空比的PWM信号到PB5的LED灯,实现“呼吸灯效果”。
    在这里插入图片描述
while (1)
  {
	  for(uint8_t i=1;i<100;i++)
	  {
		  TIM_OC_InitTypeDef sConfigOC = {0};
		  sConfigOC.OCMode = TIM_OCMODE_PWM1;
		  sConfigOC.Pulse = PERIOD_VALUE/i;
		  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
		  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
		  if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
		  {
		    Error_Handler();
		  }
		  if (HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_2) != HAL_OK)
		  {
		    /* PWM Generation Error */
		    Error_Handler();
		  }
		  HAL_Delay(30);
	  }
	  HAL_Delay(500);
	  for(uint8_t i=100;i>0;i--)
	  {
		  TIM_OC_InitTypeDef sConfigOC = {0};
		  sConfigOC.OCMode = TIM_OCMODE_PWM1;
		  sConfigOC.Pulse = PERIOD_VALUE/i;
		  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
		  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
		  if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
		  {
		    Error_Handler();
		  }
		  if (HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_2) != HAL_OK)
		  {
		    /* PWM Generation Error */
		    Error_Handler();
		  }
		  HAL_Delay(30);
	  }
	  HAL_Delay(500);
  1. 串口通信命令格式,例如,PC端发送 0xaa 0x01 0x03 0x04 0x55,表示点亮LD3,利用HAL_UART库函数实现题目功能
    在这里插入图片描述
//使用查询方式
  while (1)
  {
	  if(HAL_UART_Receive(&huart2, aRxbuf, 5, 100) == HAL_OK){
		  if (aRxbuf[0] != 0xaa){
			  HAL_UART_Transmit(&huart2, aTxbuf1, sizeof(aTxbuf1), 100);
			  continue;
		  }
		  if (aRxbuf[4] != 0x55){
			  HAL_UART_Transmit(&huart2, aTxbuf2, sizeof(aTxbuf2), 100);
			  continue;
		  }
		  if (aRxbuf[1]+aRxbuf[2] != aRxbuf[3]){
			  HAL_UART_Transmit(&huart2, aTxbuf3, sizeof(aTxbuf3), 100);
			  continue;
		  }
		  if (aRxbuf[1] == 0x01){
			  switch(aRxbuf[2]){
			  case 0x01:HAL_GPIO_WritePin(LED1_RED_GPIO_Port, LED1_RED_Pin, GPIO_PIN_SET);  break;
			  case 0x02:HAL_GPIO_WritePin(LED2_GREEN_GPIO_Port, LED2_GREEN_Pin, GPIO_PIN_SET);  break;
			  case 0x03:HAL_GPIO_WritePin(LED3_BLUE_GPIO_Port, LED3_BLUE_Pin, GPIO_PIN_SET);  break;
			  case 0x04:HAL_GPIO_WritePin(LED4_YELLOW_GPIO_Port, LED4_YELLOW_Pin, GPIO_PIN_SET);  break;
			  }
		  }
		  if (aRxbuf[1] == 0x02){
  			switch(aRxbuf[2]){
  			  case 0x01:HAL_GPIO_WritePin(LED1_RED_GPIO_Port, LED1_RED_Pin, GPIO_PIN_RESET);  break;
  			  case 0x02:HAL_GPIO_WritePin(LED2_GREEN_GPIO_Port, LED2_GREEN_Pin, GPIO_PIN_RESET);  break;
  			  case 0x03:HAL_GPIO_WritePin(LED3_BLUE_GPIO_Port, LED3_BLUE_Pin, GPIO_PIN_RESET);  break;
  			  case 0x04:HAL_GPIO_WritePin(LED4_YELLOW_GPIO_Port, LED4_YELLOW_Pin, GPIO_PIN_RESET);  break;
  			  }
  		  }
	  }
  }
//使用中断方式,注意要在main函数里面,先使能接收,即添加一句HAL_UART_Receive_IT(&huart2, aRxbuf, 5);
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	HAL_UART_Receive_IT(&huart2, aRxbuf, 5);
	if (aRxbuf[0] != 0xaa){
		HAL_UART_Transmit_IT(&huart2, aTxbuf1, sizeof(aTxbuf1));
		return;
		}
	if (aRxbuf[4] != 0x55){
		HAL_UART_Transmit_IT(&huart2, aTxbuf2, sizeof(aTxbuf2));
		return;
	}
	if (aRxbuf[1]+aRxbuf[2] != aRxbuf[3]){
		HAL_UART_Transmit_IT(&huart2, aTxbuf3, sizeof(aTxbuf3));
		return;
	}
	if (aRxbuf[1] == 0x01){
		switch(aRxbuf[2]){
		case 0x01:HAL_GPIO_WritePin(LED1_RED_GPIO_Port, LED1_RED_Pin, GPIO_PIN_SET);  break;
		case 0x02:HAL_GPIO_WritePin(LED2_GREEN_GPIO_Port, LED2_GREEN_Pin, GPIO_PIN_SET);  break;
		case 0x03:HAL_GPIO_WritePin(LED3_BLUE_GPIO_Port, LED3_BLUE_Pin, GPIO_PIN_SET);  break;
		case 0x04:HAL_GPIO_WritePin(LED4_YELLOW_GPIO_Port, LED4_YELLOW_Pin, GPIO_PIN_SET);  break;
		}
	}
	if (aRxbuf[1] == 0x02){
		switch(aRxbuf[2]){
		case 0x01:HAL_GPIO_WritePin(LED1_RED_GPIO_Port, LED1_RED_Pin, GPIO_PIN_RESET);  break;
		case 0x02:HAL_GPIO_WritePin(LED2_GREEN_GPIO_Port, LED2_GREEN_Pin, GPIO_PIN_RESET);  break;
		case 0x03:HAL_GPIO_WritePin(LED3_BLUE_GPIO_Port, LED3_BLUE_Pin, GPIO_PIN_RESET);  break;
		case 0x04:HAL_GPIO_WritePin(LED4_YELLOW_GPIO_Port, LED4_YELLOW_Pin, GPIO_PIN_RESET);  break;
		}
	}
}
  • 52
    点赞
  • 219
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 14
    评论
1、 ARM微处理器有 7种工作模式,它们分为两类 非特权模式 、 特权模式 。其中用户模式属于 非特权模式 2、 ARM支持两个指令集, ARM核因运行的指令集不同,分别有两个状态 ARM 、 Thumb ,状态寄存器CPSR的 T 位反映了处理器运行不同指令的当前状态 3、 ARM核有多个寄存器,其中大部分用于通用寄存器,有小部分作为专用寄存器, R15 寄存器用于存储PC,R13通常用来存储 SP 4、 ARM处理器有两种总线架构,数据和指令使用同一接口的是 冯诺依曼 ,数据和指令分开使用不同接口的是 哈佛结构 1. 下列不是嵌入式系统特点的是: A. 系统内核小 B. 专用性强 C. 系统精简 D. 实时性要求不高 2. 关于ARM汇编和C语言混合编程下列错误的是: A.C语言中可以直接嵌入某些汇编指令 B. C语言中可以调用汇编的子程序 C. 汇编程序中可以调用C语言的函数 D. C语言嵌入的汇编指令时,不可以使用C的变量 3. 关于ATPCS规则,说法错误的是: A. 只能使用R0-R3来传递参数 B. R13为堆栈指针SP,需要保护 C. R14为连接寄存器,用于存放程序返回地址 D. 单字的返回值存放在R0 4. 关于交叉编译描述正确的是: A. 编译器运行在目标机,生成的可执行文件在宿主机上运行 B.编译器运行在宿主机,生成的可执行文件在宿主机上运行 C.编译器运行在目标机,生成的可执行文件在目标机上运行 D.编译器运行在宿主机,生成的可执行文件在目标机上运行 5. 建立嵌入式Linux开发环境中,使用Bootp协议的直接目的是: A. 分配宿主机的IP地址 B. 分配目标机的IP地址 C. 用于宿主机和目标机之间通讯 D. 用于监控目标机的运行。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

瓜洲大大

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值