1、讲一下STM32时钟系统
时钟系统类似于脉搏,控制着CPU的命脉,STM32的时钟源又不像51的时钟源那么单一,因为STM32的MCU较为复杂,且外设较多,并不是所有的外设都需要那么高的时钟频率,而且较高的频率对功耗和抗干扰都不具优势,所以对复杂的MCU系统往往采取多个时钟源,STM32有5个时钟源,HSI、HSE、PLL(这三个往往作为系统时钟)、LSI(外部看门狗时钟)、LSE(STC时钟源)。
2、c语言中堆和栈的区别
1、数据结构上:
- 都是一种数据项按序排列的数据结构。
- 栈:一种具有先进后出性质的数据结构
- 堆:堆是一种经过排序的树形数据结构、通常我们所说的堆的数据结构,是指二叉堆、虽然存储有序,但是我们取值是可以任意的。
2、申请与释放方式
- 栈:系统自动分配空间,生命周期在函数运行期间,运行结束便被系统回收
- 堆:程序员手动分配,如果不手动释放,所占用空间将一直存在
3、申请效率
- 栈:由系统自动分配,速度较快。但程序员是无法控制的。
- 堆:是由new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便。
4、申请空间大小限制:
- 栈:栈是向低地址扩展的数据结构,是一块连续的内存的区域,这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的
- 堆:堆的大小一般看内存的大小。
5、存放信息
- 栈: 在函数调用时,第一个进栈的是主函数中函数调用后的下一条指令(函数调用语句的下一条可执行语句)的地址,然后是函数的各个参数,在大多数的C编译器中,参数是由右往左入栈的,然后是函数中的局部变量。注意静态变量是不入栈的。
当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的地址,也就是主函数中的下一条指令,程序由该点继续运行。 - 堆:一般是在堆的头部用一个字节存放堆的大小。堆中的具体内容有程序员安排
3、假如一个单片机上电之后不运行?这是为什么?
- 检查晶振工作是否正常
- 检测EA脚是否拉低。单片机EA引脚表示存取外部程序代码之意,低电平动作,当此引脚接低电平后,系统会取用外部的程序代码(存于外部EPROM中)来执行程序。EA引脚必须接低电平,因为其内部无程序存储器空间。
4、精度和分辨率有什么区别
像数字化的温度传感器,一般精度指的是传感器读回的数据与绝对温度的差值,而分辨率指的是传感器能感知的最小温度变化。
5、你来说一下中断的处理流程是什么样子的?
- 中断响应:设置程序断点,并将断点地址压入栈进行保护,接着将程序转到中断服务程序的入口地址。
- 中断处理:从中断服务程序的第一条指令开始执行直到返回指令为止。
- 中断返回:中断处理程序的最后一条指令是中断返回指令RETI,该指令的作用将断点地址从栈中弹出,程序继续从断点地址开始执行
6、中断的优点
- 实时性
- 充分利用系统资源,提高CPU效率
7、讲一下grep的作用
查找相应文件中符合条件的字符串
8、I2C的开始信号、I2C配置主机模式端口该怎么配置
- 开始信号: SCL为高电平期间,SDA由高电平向低电平进行跳边,产生开始信号。
- 主机模式端口的配置:
-
硬件模式:端口设置为复用模式,复用为I2C、开漏输出、既不上拉也不下拉。
void I2C1_GPIO_Configuration(void) { GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //复用模式 GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;//必须设置为开漏输出,实现iic的线与逻辑 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; //不上拉也不下拉 GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_PinAFConfig(GPIOB,GPIO_PinSource6,GPIO_AF_I2C1); GPIO_PinAFConfig(GPIOB,GPIO_PinSource7,GPIO_AF_I2C1); }
- 软件模拟:设置普通输出模式,推挽输出、配置上拉电阻
void IIC_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//使能GPIOB时钟 //GPIOB8,B9初始化设置 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式 GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉 GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化 IIC_SCL=1; IIC_SDA=1; }
-
9、讲一下extern的作用
-
声明外部变量
-
在C++文件中调用C方式编译的函数
extern "C" { ... C++可以重定义,而C中没有重定义 }
10、讲一下static的作用
- 函数内部的变量值保持不变
- 模块内、函数外的变量,模块内的任意函数都能使用,但模块外的函数无法调用
- 定义在模块内的函数,模块外无法调用。、
11、讲解下GPIO是什么,有几种模式
- GPIO就是通用的输入输出端口
- 有8中模式:4输入(上拉输入、下拉输入、浮空输入、模拟输入)、4输出(推挽输出、开漏输出、复用推挽输出、复用开漏输出)
12、进程通信的方法
- 管道
- FIFO
- 消息队列
- 信号量
- 共享内存
13、MQTT与HTTP的区别
- MQTT以数据为中心,传输量小、速度快
- HTTP以文本为中心,传输量大,速度较慢
- 两个都是基于TCP(传输层之上的),都是属于应用层的协议,MQTT协议一般采取明文传送,而HTTP可以采用HTTPS进行加密。
14、MQTT的消息类型有哪些
- 连接
- 发布
- 订阅
- 订阅确认
- 取消订阅
15、STM32-ADC配置
- 引脚配置
- 使能引脚时钟与ADC时钟
- 设置端口为模拟输入,不带上下拉电阻
- 设置ADC的通用控制寄存器CCR
- 设置ADC的采样模式-独立模式
- 设置ADC的分频系数
- 初始化ADC参数
- 设置ADC的分辨率
- 转换方式 - 关闭连续转换模式
- 设置对齐方式 - 右对齐
- 开启AD转换器
void Adc_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
ADC_CommonInitTypeDef ADC_CommonInitStructure;
ADC_InitTypeDef ADC_InitStructure;
//①开启 ADC 和 GPIO 相关时钟和初始化 GPIO
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);//使能 GPIOA 时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); //使能 ADC1 时钟
//先初始化 ADC1 通道 5 IO 口
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;//PA5 通道 5
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;//模拟输入
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;//不带上下拉
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化
RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC1,ENABLE); //ADC1 复位
RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC1,DISABLE); //复位结束
//②初始化通用配置
ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;//独立模式
ADC_CommonInitStructure.ADC_TwoSamplingDelay =
ADC_TwoSamplingDelay_5Cycles;//两个采样阶段之间的延迟 5 个时钟
ADC_CommonInitStructure.ADC_DMAAccessMode =
ADC_DMAAccessMode_Disabled; //DMA 失能
ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4;//预分频 4 分频。
//ADCCLK=PCLK2/4=84/4=21Mhz,ADC 时钟最好不要超过 36Mhz
ADC_CommonInit(&ADC_CommonInitStructure);//初始化
//③初始化 ADC1 相关参数
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;//12 位模式
ADC_InitStructure.ADC_ScanConvMode = DISABLE;//非扫描模式
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;//关闭连续转换
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
//禁止触发检测,使用软件触发
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//右对齐
ADC_InitStructure.ADC_NbrOfConversion = 1;//1 个转换在规则序列中
ADC_Init(ADC1, &ADC_InitStructure);//ADC 初始化
//④开启 ADC 转换
ADC_Cmd(ADC1, ENABLE);//开启 AD 转换器
}
//获得 ADC 值
//ch:通道值 0~16: ch: @ref ADC_channels
//返回值:转换结果
u16 Get_Adc(u8 ch)
{
//设置指定 ADC 的规则组通道,一个序列,采样时间
ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_480Cycles );
ADC_SoftwareStartConv(ADC1); //使能指定的 ADC1 的软件转换启动功能
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束
return ADC_GetConversionValue(ADC1); //返回最近一次 ADC1 规则组的转换结果
}
//获取通道 ch 的转换值,取 times 次,然后平均
//ch:通道编号 times:获取次数
//返回值:通道 ch 的 times 次转换结果平均值
u16 Get_Adc_Average(u8 ch,u8 times)
{
u32 temp_val=0; u8 t;
for(t=0;t<times;t++)
{
temp_val+=Get_Adc(ch); delay_ms(5);
}
return temp_val/times;
}