Web前端最全零基础蓝桥杯嵌入式教程(2),字节跳动审核岗面试问题

其实前端开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。

这里再分享一个复习的路线:(以下体系的复习资料是我从各路大佬收集整理好的)

开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

《前端开发四大模块核心知识笔记》

最后,说个题外话,我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。

我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在IT学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。

566f0cfe77554275bdfef0f78b2f54bb.png能选择的行数Line为0到9一共十行。

高亮显示

如果需要高亮显示,在写sprintf和LCD_DisplayStringLine之前写一下需要高亮的颜色的背景色设置语句,以设置line0为黄色高亮显示为例,其他行不变。

LCD_SetBackColor(Yellow);
Sprintf(text,"numbe",1);
LCD_DisplayStringLine(Line0,(uint8_t *)text,);

LCD_SetBackColor(Black);
Sprintf(text,"numbe",1);
LCD_DisplayStringLine(Line0,(uint8_t *)text,);

lcd翻转显示

在所给的lcd液晶控制器资料中手册中,搜索diretion能够找到对于显示方向的描述df47efa0d41649e7b6247d7a44ff8d1c.pngSS位控制横向扫描方向,GS位控制纵向扫描方向,搜索GS和SS,能看到分别所在的寄存器位置875a554609da44e7984785523040792a.pngd422e481748a46f98060335822155eb3.png

搜索60h和01h,能找到GS和SS设置。这里的60和01都是16进制,对应1和96号寄存器。0464fc51c4cd47049a57ee5ccac33c7c.png7c9c478c962b44d7aed75df8283d7f0b.pnge30945ff649845fca4d7ae6b6185c6fa.png

lcd.c中将函数void REG_932X_Init(void)复制粘贴到下方,更名为void REG_932X_Init1(void),其中1和96号寄存器对应的SS和GS的值更改即可,此时看到代码注释给了需要更改的值,更改即可。

60f2832e28a64f29bee8d71d5dded3e1.png

1f3eb06e55554f1889cd52943e4c8d00.png

void REG_932X_Init1(void)
{
    LCD_WriteReg(R227, 0x3008);   // Set internal timing
    LCD_WriteReg(R231, 0x0012); // Set internal timing
    LCD_WriteReg(R239, 0x1231);   // Set internal timing
    LCD_WriteReg(R1, 0x0100);   // set SS and SM bit		  //0x0100
    LCD_WriteReg(R2, 0x0700);   // set 1 line inversion
    LCD_WriteReg(R3, 0x1030);     // set GRAM write direction and BGR=1.
    LCD_WriteReg(R4, 0x0000);     // Resize register
    LCD_WriteReg(R8, 0x0207);     // set the back porch and front porch
    LCD_WriteReg(R9, 0x0000);     // set non-display area refresh cycle ISC[3:0]
    LCD_WriteReg(R10, 0x0000);    // FMARK function
    LCD_WriteReg(R12, 0x0000);  // RGB interface setting
    LCD_WriteReg(R13, 0x0000);    // Frame marker Position
    LCD_WriteReg(R15, 0x0000);  // RGB interface polarity
    /**************Power On sequence ****************/
    LCD_WriteReg(R16, 0x0000);    // SAP, BT[3:0], AP, DSTB, SLP, STB
    LCD_WriteReg(R17, 0x0007);    // DC1[2:0], DC0[2:0], VC[2:0]
    LCD_WriteReg(R18, 0x0000);  // VREG1OUT voltage
    LCD_WriteReg(R19, 0x0000);    // VDV[4:0] for VCOM amplitude
    //	Delay_Ms(200);                    // Delay 200 MS , Dis-charge capacitor power voltage
    HAL_Delay(200);
    LCD_WriteReg(R16, 0x1690);    // SAP, BT[3:0], AP, DSTB, SLP, STB
    LCD_WriteReg(R17, 0x0227);  // R11H=0x0221 at VCI=3.3V, DC1[2:0], DC0[2:0], VC[2:0]
    //	Delay_Ms(50);      // Delay 50ms
    HAL_Delay(50);
    LCD_WriteReg(R18, 0x001D);  // External reference voltage= Vci;
    //	Delay_Ms(50);      // Delay 50ms
    HAL_Delay(50);
    LCD_WriteReg(R19, 0x0800);  // R13H=1D00 when R12H=009D;VDV[4:0] for VCOM amplitude
    LCD_WriteReg(R41, 0x0014);  // R29H=0013 when R12H=009D;VCM[5:0] for VCOMH
    LCD_WriteReg(R43, 0x000B);    // Frame Rate = 96Hz
    //	Delay_Ms(50);      // Delay 50ms
    HAL_Delay(50);
    LCD_WriteReg(R32, 0x0000);  // GRAM horizontal Address
    LCD_WriteReg(R33, 0x0000);  // GRAM Vertical Address
    /* ----------- Adjust the Gamma Curve ---------- */
    LCD_WriteReg(R48, 0x0007);
    LCD_WriteReg(R49, 0x0707);
    LCD_WriteReg(R50, 0x0006);
    LCD_WriteReg(R53, 0x0704);
    LCD_WriteReg(R54, 0x1F04);
    LCD_WriteReg(R55, 0x0004);
    LCD_WriteReg(R56, 0x0000);
    LCD_WriteReg(R57, 0x0706);
    LCD_WriteReg(R60, 0x0701);
    LCD_WriteReg(R61, 0x000F);
    /* ------------------ Set GRAM area --------------- */
    LCD_WriteReg(R80, 0x0000);    // Horizontal GRAM Start Address
    LCD_WriteReg(R81, 0x00EF);    // Horizontal GRAM End Address
    LCD_WriteReg(R82, 0x0000);  // Vertical GRAM Start Address
    LCD_WriteReg(R83, 0x013F);  // Vertical GRAM Start Address
    LCD_WriteReg(R96, 0xA700);  // Gate Scan Line		  0xA700
    LCD_WriteReg(R97, 0x0001);  // NDL,VLE, REV
    LCD_WriteReg(R106, 0x0000); // set scrolling line
    /* -------------- Partial Display Control --------- */
    LCD_WriteReg(R128, 0x0000);
    LCD_WriteReg(R129, 0x0000);
    LCD_WriteReg(R130, 0x0000);
    LCD_WriteReg(R131, 0x0000);
    LCD_WriteReg(R132, 0x0000);
    LCD_WriteReg(R133, 0x0000);
    /* -------------- Panel Control ------------------- */
    LCD_WriteReg(R144, 0x0010);
    LCD_WriteReg(R146, 0x0000);
    LCD_WriteReg(R147, 0x0003);
    LCD_WriteReg(R149, 0x0110);
    LCD_WriteReg(R151, 0x0000);
    LCD_WriteReg(R152, 0x0000);
    /* Set GRAM write direction and BGR = 1 */
    /* I/D=01 (Horizontal : increment, Vertical : decrement) */
    /* AM=1 (address is updated in vertical writing direction) */
    LCD_WriteReg(R3, 0x01018);    //0x1018

    LCD_WriteReg(R7, 0x0173);   // 262K color and display ON
}

随后在lcd.h中将新的函数声明。

void REG_932X_Init1(void);

通过搜索发现此函数是在lcd初始化函数中调用的,所以在需要反转显示的位置前调用LCD_Clear(Black)清屏后调用新的修改后的函数void REG_932X_Init1(void)。97124ce6086a4836b6f54bece5dffa38.png

PWM

以PA6和PA7为例,引脚配置为CH1通道,CH1N为互补PWM波,不选,选择定时器和对应的CH1的模式,以TIM16为例,TIM17同理。预分频(psc):CPU运行频率先经过它分频再进入计时器,如CPU运行在 x Mhz 下,预分频为 y,那进入计时器的频率也就为 x/(y+1) Mhz(因为从0计数,所以是y+1)。自动重装值(arr):指一次周期的计数长度。脉冲长度(pulse):指输出脉冲的计数长度。

频率=外部总线频率/(PSC+1)/(ARR+1),占空比为pulse/(ARR+1),PSC,ARR,pulse在代码中可以重新设置和调整:


/*

__HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_1,180); //修改CCR寄存器
__HAL_TIM_SET_AUTORELOAD(&htim2,1440); //修改ARR寄存器,没有通道限制,整个定时器一起改
__HAL_TIM_SET_PRESCALER(TIM_TypeDef* TIMx, uint32_t Prescaler);//修改预分频系数
举一个例子:
__HAL_TIM_SET_PRESCALER(&htim2, 1000);
这条语句就是把定时器二的预分频系数设为1000
*/

a0f34979b3664fa0a44908baf20cfd6b.pngfcd1c0242c624be690d7978ab009cb49.png

my_main.h代码

void pwm_proce(void);

my_main.c代码

int pa6_duty=200;
int pa7_duty=100;

void pwm_proce(void)
{
	__HAL_TIM_SetCompare(&htim16,TIM_CHANNEL_1,pa6_duty);
	__HAL_TIM_SetCompare(&htim16,TIM_CHANNEL_1,pa7_duty);
}

setup中开启

HAL_TIM_PWM_Start(&htim16,TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim17,TIM_CHANNEL_1);

输入捕获频率和占空比

可用CH1和CH2通道的引脚(主要)

通过跳线帽连接到PA15和PB4引脚,选择CH1通道,只有ch1和ch2可以从模式清除,这里选择了TIM2和TIM3的CH1。b84598743cd4474bb640bfe6d633a19c.png

31064fee831c4949998ef7da6e232480.pngbadcdc8f1d2549c4aaded72eabbbac50.png

TI1FP1对上升沿敏感,TI1FP2对下降沿敏感,CNT计数器在80MHZ经过分频后的频率下进行计数(比如分频80,则一微秒计时一次),而ccr1和ccr2则会在上升和下降沿来临时记录下cnt的值,cnt通过从模式在上升沿来临时,ccr1存下数据后归位。由此ccr1就是一个周期的计数,ccr2就是高电平时间的计数。输入到从模式控制器的信号只能是TI1FP1和TI1FP2,所以只能用CH1和CH2通道2ed1cb9473df40be945bdc3f4c7e29cd.png

tim2配置,tim3同理,channel1和2的直接模式和间接模式:所用的引脚直接相连的通道号为直接模式,如果引脚是channel2,则channel2为直接模式,否则间接模式占用直接相连的通道,直接模式会另开一个引脚

5d1ca50dbfd34fcaaabaf7cef21e42f7.png

.h

void in_pro(void);

setup中开启IC输入捕获(频率和占空比分别是上升和下降的通道,防止开错或者忘开,都开启)

	HAL_TIM_IC_Start(&htim2,TIM_CHANNEL_1);
	HAL_TIM_IC_Start(&htim2,TIM_CHANNEL_2);
	HAL_TIM_IC_Start(&htim3,TIM_CHANNEL_1);
	HAL_TIM_IC_Start(&htim3,TIM_CHANNEL_2);

.c

float frq1=0,frq2=0;
float duty1=0,duty2=0;

void in_pro(void)
{
	frq1=1000000.0f/(HAL_TIM_ReadCapturedValue(&htim2,TIM_CHANNEL_1)+1);
	duty1=(HAL_TIM_ReadCapturedValue(&htim2,TIM_CHANNEL_2)+1)*100.0f/(HAL_TIM_ReadCapturedValue(&htim2,TIM_CHANNEL_1)+1);
	
	frq2=1000000.0f/(HAL_TIM_ReadCapturedValue(&htim3,TIM_CHANNEL_1)+1);
	duty2=(HAL_TIM_ReadCapturedValue(&htim3,TIM_CHANNEL_2)+1)*100.0f/(HAL_TIM_ReadCapturedValue(&htim3,TIM_CHANNEL_1)+1);
}

不可用CH1和CH2的引脚(备用)

和能使用从模式清零的方式相比,此方式通用性更好,有的引脚不能使用CH1和CH2,区别在于

1.需首先开启的输入捕获是在中断方式下,函数多了"IT"。

2.判断中断的计时器号,然后判断htim->Channel==HAL_TIM_ACTIVE_CHANNEL_1

3.此方式在读取两个通道的寄存器的值后需要手动归零计时器并且重新打开输入捕获的中断模式。Clock Source选择Integral Clock,Channel1选择 Input Capture direct modeb6d18dde0a574bd198f0977f7b406fb2.png

对方波的一个周期的上升沿时间计数,frq=(80000000/80)/得到的时间值。测量占空比的原理:高电平的时间比上一个周期的时间。在定时器的另外一个通道,配置成间接模式Input Capture indirect mode,直接模式去测上升沿,间接模式去测下降沿。Polarity Selection一个是Rinsing Edge,另一个是falling Edge。打开中断使能。7ce30c72c50b47249782738f9251e8df.png887b8a01580e43358ebc674fd5e9f189.png

剩下一个定时器TIM3同理。

setup初始化的地方把定时器中断打开。

HAL_TIM_IC_Start_IT(&htim2,TIM_CHANNEL_1);
HAL_TIM_IC_Start_IT(&htim2,TIM_CHANNEL_2);
HAL_TIM_IC_Start_IT(&htim3,TIM_CHANNEL_1);
HAL_TIM_IC_Start_IT(&htim3,TIM_CHANNEL_2);

my_main.h

//

my_main.c

double val1a=0,val2a=0;
uint val1b=0,val2b=0;

uint frq1=0,frq2=0;
float duty1=0,duty2=0;

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance==TIM2)
	{
		if(htim->Channel==HAL_TIM_ACTIVE_CHANNEL_1)
		{
			val1a=HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_1);
			val1b=HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_2);
			__HAL_TIM_SetCounter(htim,0);
			frq1=(80000000/80)/val1a;
			duty1=(val1b/val1a)*100;
			HAL_TIM_IC_Start(htim,TIM_CHANNEL_1);
			HAL_TIM_IC_Start(htim,TIM_CHANNEL_2);
		}
	}
	
	if(htim->Instance==TIM3)
	{
		if(htim->Channel==HAL_TIM_ACTIVE_CHANNEL_1)
		{
			val2a=HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_1);
			val2b=HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_2);
			__HAL_TIM_SetCounter(htim,0);
			frq2=(80000000/80)/val2a;
			duty2=(val2b/val2a)*100;
			HAL_TIM_IC_Start(htim,TIM_CHANNEL_1);
			HAL_TIM_IC_Start(htim,TIM_CHANNEL_2);
		}
	}
}

HAL\_TIM\_IC\_Start: 这个函数用于启动定时器的输入捕获模式,但不启用中断。当只需要获取输入捕获的值而不需要中断处理时,可以使用这个函数。

HAL\_TIM\_IC\_Start\_IT: 这个函数不仅启动了定时器的输入捕获模式,还启用了中断。这样,当输入捕获事件发生时,会触发中断,并调用相应的中断处理函数。这个函数适用于需要在输入捕获事件发生时执行某些特定操作的情况。

如果中断回调函数太长记不住也可以在如下文件的后部分找到3fe9083cb50a48bd9f7c0f6b460a22c4.png

ADC_DMA

af0c2d1fff1f4af4a312f4ceb4379af8.jpege6dd73a869a742c3a03f506adb4c3f74.jpegb2b06e5520a341d496a5328efcaa0999.jpeg

单通道

用到接口PB15和PB125975740ea58d43f7a4eab83041ed76df.png选择ADC IN,左边Analog里面找到PB15用到的ADC1,ADC1里面找到用到的IN 11,选择single-ended,ADC2中的IN15同理。采样时间增大对于稳定结果的作用有限,这里采用一个过采样。cb033f2648564513b452b0198608f1c8.png

.h文件代码

#include "adc.h"
float GETADC_value(ADC_HandleTypeDef *ADCx);

setup校准ADC1

HAL_ADCEx_Calibration_Start(&hadc2,ADC_SINGLE_ENDED);

.c文件代码

float GETADC_value(ADC_HandleTypeDef *ADCx)
{
	float prpt;
	HAL_ADC_Start(ADCx);
	prpt=HAL_ADC_GetValue(ADCx);
	return prpt*3.3f/65536.0f;
}

一般要求浮点保留两位小数,在LCD显示时形式为  V:=%.2f       V:=后面要跟数字,数字是浮点型保留两位小数

定义函数时要写函数返回值类型,后面形参括号里面写形参或者void,主函数调用时就只用写函数名加分号。

获取值代码

ADC_value=GETADC_value(&hadcx);//传参数例如&hadc1给上面的ADCx

DMA(建议)

使用PB12和PB14演示,PB15已经用以上单通道演示过。

使能引脚单端触发,添加DMA设置为扫描模式。参数设置中通道数设置为2,使能扫描模式、连续请求模式、DMA连续请求。使能定时请求,通道采样时间尽可能大,否则占用过多CPU程序可能卡死。

0be66b381dde48b682ac374c7a7f9e48.png7bd493ec927041b090bb4e7161baa316.png

开头设置缓冲区

uint16_t adc_buf[2];

setup中校准和开启DMA

HAL_ADCEx_Calibration_Start(&hadc1,ADC_SINGLE_ENDED);
HAL_ADC_Start_DMA(&hadc1,(uint32_t *)adc_buf,2);

数据存在了缓冲区adc_buf[0]和adc_buf[1],可以随时使用,例如显示在屏幕上 ,但是要经过一下处理,例如保留三位小数adc_buf[0]*3.3f/4096.0f,adc_buf[1]*3.3f/4096.0f

char text[30];
sprintf(text,"ADC1:%.3f,2:%.3f",adc_buf[0]*3.3f/4096.0f,adc_buf[1]*3.3f/4096.0f);
LCD_DisplayStringLine(Line0,(uint8_t *)text);

USART

空闲中断回调函数(简单)

接受时所使用的空闲中断回调函数是只有在V1.4.0及其之后的版本固件包才有,没有此函数需要用中断回调函数,会麻烦的多,但是可以实现,见后文。

关于格式化输入输出:

例:sscanf(rxdata,“%c”,&uart_flag[3]);中的%c是char类型,也可以转化为string类型,需要写为%xs,x为数字,是要转化的长度,例如

sscanf(rxdata,"%4s:%4s:%12s",car_type,car_data,car_time);

在这个sscanf语句中,冒号在格式字符串中的作用是用于匹配输入字符串中的冒号字符。这表示在rxdata中,字符串应该以冒号分隔,并且sscanf将会按照这种格式解析输入字符串。
具体来说:
“%4s” 表示读取最多4个非空格字符的字符串,这里用于匹配 car_type。“:” 表示在输入字符串中匹配冒号字符。
“%4s” 再次表示读取最多4个非空格字符的字符串,用于匹配 car_data。“:” 再次表示匹配冒号。
“%12s” 表示读取最多12个非空格字符的字符串,用于匹配 car_time。
这样的格式说明符确保了输入字符串的特定格式,其中每个字符串之间由冒号分隔。如果rxdata不符合这种格式,sscanf可能无法正确解析字符串,或者解析结果可能不符合预期。

C语言中,& 操作符用于获取变量的地址。在 sscanf 函数中,如果你想将读取到的值存储到变量中,需要传递该变量的地址。如果不使用 &,则传递的是变量的值,而不是地址。
对于数组来说,数组名本身就是数组的地址。所以,当你传递数组名时,不需要使用 &。但如果你传递数组的某个元素(如字符或者整型数),那么需要使用 & 来获取该元素的地址。如下:

char usart_flag[5];
 
// 不使用&,传递的是数组的地址
sscanf(rxdata, "%c", usart_flag);
 
// 使用&,传递的是数组的第一个元素的地址
sscanf(rxdata, "%c", &usart_flag[0]);

Cubemx配置,在通信位置connectivity选择uart1,mode改成第二项异步模式Asynchronous。没有配置过LCD的话会默认使用PC4和PC5,需要手动改成PA10和PA9。Baud rate波特率一般使用9600,nvic setting中断打开。ef2f375c44ec49cebb109f2a743351fe.png

空闲中断回调函数位置,建议复制粘贴

c9de5c0d18d64030b8209efbecac843c.png setup

HAL_UARTEx_ReceiveToIdle_IT(&huart1,(uint8_t *)uart_rx,50);

开启中断只能使用一次,所以接收函数最后还要再开启一次

.h

#include "usart.h"
#include "string.h"

void uart_tx_proce(void);

.c(以接收到四位字符串为例)

char uart_tx[50];
char uart_rx[50];
char text1 [4]="0000";
char text[30];


void uart_tx_proce(void)
{
	sprintf(uart_tx,"tx");
	HAL_UART_Transmit(&huart1,(uint8_t *)uart_tx,strlen(uart_tx),50);
}

void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
	sscanf(uart_rx,"%3s",text1);
	 sprintf(text,"text1:%s",text1);
	 LCD_DisplayStringLine(Line1,(uint8_t *)text);
	HAL_UARTEx_ReceiveToIdle_IT(&huart1,(uint8_t *)uart_rx,50);
}

另一种中断回调函数方法(应该用不到)

.c文件中利用中断回调函数进行接收,然后进行处理(示例)及发送写法

char rxdata[30];
uint8_t rxdat;
uchar rx_pointer;
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)//接收中断
{
	rxdata[rx_pointer++]=rxdat;
	HAL_UART_Receive(&huart1,&rxdat,1,10);
}
//char uart_data[3];
void uart_rx_proce()//数据接收处理程序
{
	if(rx_pointer>0)//说明有数据被接收,进行处理
	{	/*
		if(rx_pointer=1)            恰好接收一位数据
		sscanf(rxdata,"%c",&uart_data[3]);     格式化处理接收到的数据
	
	else
	{
		char temp[20];              发送示例
		sprintf(temp,"Error");         发送示例
		HAL_UART_Transmit(&huart1,(uint8_t *)temp,strlen(temp),50);        发送示例
	}*/
		rx_pointer=0;memset(rxdata,0,30);//清零
	}
}

在 HAL_UART_RxCpltCallback 回调函数中,HAL_UART_Receive_IT 函数首先被调用,它开始等待接收一个字节的数据。然后,rxdata[rx_pointer++]=rxdat; 语句被执行,将接收到的数据存储在 rxdata 数组中,并且 rx_pointer 递增。因此,rx_pointer 表示已经接收到的数据数量。虽然 rxdata[rx_pointer++]=rxdat; 在 HAL_UART_Receive_IT 函数之后,但由于这是在回调函数中,它们实际上是异步执行的。即,当有数据可用时,回调函数被触发,首先会启动下一次接收,然后处理已接收的数据。所以,rxdata[rx_pointer++]=rxdat; 的执行确实发生在HAL_UART_Receive_IT(&huart1,&rxdat,1); 之后。

在C语言中,uint8\_t是一个无符号的8位整数类型,因此可以用来接收字符。字符在C语言中实际上是以ASCII码的形式存储的,而ASCII码的取值范围是0到255,恰好与uint8\_t类型的取值范围一致。因此,可以使用uint8\_t类型来接收字符。

main.c中进行初始化

extern uint8_t rxdat;
HAL_UART_Receive_IT(&huart1,&rxdat,1);

SYSTICK

只需要知道SysTick_Handler(void)是一毫秒进入一次的函数,至于上面编写何种功能的函数,然后放在SysTick_Handler(void)里面从而实现何种功能就根据实际而来,这里的是0.1s反转flag的函数。

//stm32Gxx_it.c里面
//------------------------------------------
int flag=0;
int count=0;
 
void sys_tim(int time_set)//time_set放在一毫秒进入一次的中断SysTick_Handler(void)里面,所以单位是毫秒
{
	count++;
	if(count==time_set)
  {
	flag=!flag;
	count=0;	
	}
}
//------------------------------------------------
void SysTick_Handler(void)
{
  /* USER CODE BEGIN SysTick_IRQn 0 */
 
  /* USER CODE END SysTick_IRQn 0 */
  HAL_IncTick();
  /* USER CODE BEGIN SysTick_IRQn 1 */
     sys_tim(100);//可以改变为其他时间
  /* USER CODE END SysTick_IRQn 1 */
}
//控制LED可在其他地方引用flag

还可以用另一种由系统设置好的变量来操作,原理一样,每1ms执行一次HAL_InTick函数36bbd4d0d1ac4ea8b4fc31eef4f9351c.png

HAL_InTick的具体作用是自增18f0562616e194fa7935175f6f1631b4c.png

在程序初始化位置定义计时节点

uint32_t 500ms;
500ms=uwTick;




在主程序中书写需要定时的操作,类似地,还可以同时存在其他时长的定时程序,但是此方法精确度不太高。

if(uwTick-500ms>500)
{
    //此处写需要具体执行的操作
    500ms=uwTick;
}

RTC实时时钟

以秒为单位进行计时,相当于钟表,配置时最下方year会自动补齐20xx,所以20不用写482d2e441bca47b7bd689e806ee3d4d8.png

.h

#include "rtc.h"

如果只读取时间,也需要把日期读一下,只有日期读完后,数据才会从影子寄存器读取。

.c,sprintf格式化部分多打几个空格清屏防止残留。

void RTC_proce(void)
{		
	RTC_TimeTypeDef time;
	RTC_DateTypeDef date;
	HAL_RTC_GetTime(&hrtc,&time,RTC_FORMAT_BIN);
	HAL_RTC_GetDate(&hrtc,&date,RTC_FORMAT_BIN);
	char text[30];
	sprintf(text,"time:%d:%d:%d     ",time.Hours,time.Minutes,time.Seconds);
	LCD_DisplayStringLine(Line0,(uint8_t *)text);
}

IIC-EEPROM

eeprom有寿命,尽量不要频繁写入,以下时序图赛场会芯片手册会提供

c2500e436c184842870a1af7cf9a869e.jpegc88b674c6b544b92869e80c7fc7cded3.jpega5584ae2f5ea4be6b8951b54382a3894.jpeg

复制到bsp文件夹并加入工程,内部是一些时钟线的配置和应答函数等,所以不需要cubemx配置

ee9ae92cac9b4a81a03de4561d475387.png

根据读写时序图编写写入和读取函数

my_main.h包含i2c_hal.h

其实前端开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。

这里再分享一个复习的路线:(以下体系的复习资料是我从各路大佬收集整理好的)

开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

《前端开发四大模块核心知识笔记》

最后,说个题外话,我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。

我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在IT学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。

  • 11
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值