总结
三个工作日收到了offer,头条面试体验还是很棒的,这次的头条面试好像每面技术都问了我算法,然后就是中间件、MySQL、Redis、Kafka、网络等等。
- 第一个是算法
关于算法,我觉得最好的是刷题,作死的刷的,多做多练习,加上自己的理解,还是比较容易拿下的。
而且,我貌似是将《算法刷题LeetCode中文版》、《算法的乐趣》大概都过了一遍,尤其是这本
《算法刷题LeetCode中文版》总共有15个章节:编程技巧、线性表、字符串、栈和队列、树、排序、查找、暴力枚举法、广度优先搜索、深度优先搜索、分治法、贪心法、动态规划、图、细节实现题
《算法的乐趣》共有23个章节:
- 第二个是Redis、MySQL、kafka(给大家看下我都有哪些复习笔记)
基本上都是面试真题解析、笔记和学习大纲图,感觉复习也就需要这些吧(个人意见)
- 第三个是网络(给大家看一本我之前得到的《JAVA核心知识整理》包括30个章节分类,这本283页的JAVA核心知识整理还是很不错的,一次性总结了30个分享的大知识点)
1. 原理
目前电视机、空调等家电大部分还是采用的红外遥控的,有时项目需要把遥控嵌入到自己的设备中,或者又是物联网需要控制家电,此时就需要智能学习和发送了,红外遥控电路图如下:
左侧为红外发送电路,右侧有红外接收电路。
● 发送端:
以NEC协议为例(实际测试中遵循NEC协议的不多),信息传输是基于38K载波,也就是说红外线是以载波的方式传递。
发送协议数据“0” = 发送载波560us + 不发送载波560us
发送协议数据“1” = 发送载波560us+ 不发送载波1680us
发送的波形如下图所示,下图中为 0 0 0 0 1 0 1
● 接收端:
在红外接收端,如果接收到红外38K载波,则IR输出为低电平,如果不是载波包括固定低电平和固定高电平则输出高电平。在IR端接收的信号如下所示:
NEC协议规定:
发送协议数据“0” = 发送载波560us + 不发送载波560us
发送协议数据“1” = 发送载波560us+ 不发送载波1680us
发送引导码 = 发送载波9000us + 不发送载波4500us
● 总结:
1、接收端收到38K载波脉冲为低电平,没有则为高电平;所以在设计发送的时候,发送低电平应该开启38KHZ的PWM,发送高电平则关闭PWM(默认为高电平)
2、数据“0” 和数据“1” 是由接收到的一个高电平和一个低电平组合而来,一般来说高电平时间等于低电平时间为数据0,其它则为1
2. 思路
思路简单,简述为: 捕获——>保存——>发射
先捕获一个红外遥控按键的全部信息,不管内容是什么,再保存到flash中,就是多个高低电平的持续时间,然后再一一发射出去。这样不管是什么协议都能成功。
3. 红外遥控接收
3.1 初始化定时器
具体见代码和详细的注释:
// ir\_inputCapture\_send.c
/\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
\* @brief 定时器16输入捕获初始化/红外遥控初始化、设置IO以及TIM16\_CH1的输入捕获、10ms溢出
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/
void TIM16\_Remote\_Init(void)
{
TIM_IC_InitTypeDef TIM16_CH1Config;
TIM16_Handler.Instance = TIM16; //通用定时器16
TIM16_Handler.Init.Prescaler=(48-1); //预分频器,1M的计数频率,1us加1.
TIM16_Handler.Init.CounterMode=TIM_COUNTERMODE_UP; //向上计数器
TIM16_Handler.Init.Period = (60000-1); //自动装载值,16位最大65536,此处设置60ms的计时
TIM16_Handler.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1; //时钟分频因子
HAL\_TIM\_IC\_Init(&TIM16_Handler);
//初始化TIM1输入捕获参数
TIM16_CH1Config.ICPolarity = TIM_INPUTCHANNELPOLARITY_FALLING; //注意下降沿捕获
TIM16_CH1Config.ICSelection=TIM_ICSELECTION_DIRECTTI; //映射到TI4上
TIM16_CH1Config.ICPrescaler=TIM_ICPSC_DIV1; //配置输入分频,不分频
TIM16_CH1Config.ICFilter=0x03; // 0 //IC4F=0003 8个定时器时钟周期滤波
HAL\_TIM\_IC\_ConfigChannel(&TIM16_Handler, &TIM16_CH1Config, TIM_CHANNEL_1);//配置TIM4通道4
\_\_HAL\_TIM\_ENABLE\_IT(&TIM16_Handler,TIM_IT_UPDATE); //使能更新中断
HAL\_TIM\_IC\_Stop\_IT(&TIM16_Handler,TIM_CHANNEL_1);
}
// stm32f0xx\_hal\_msp.c.c
//定时器16底层驱动,时钟使能,引脚配置
//此函数会被上述的HAL\_TIM\_IC\_Init()调用
//htim:定时器句柄
void HAL\_TIM\_IC\_MspInit(TIM_HandleTypeDef \*htim)
{
GPIO_InitTypeDef GPIO_InitStruct;
if(htim->Instance==TIM16)
{
/\*\*\*\*\*\*\*\*\*\*\*\*TIM16\_CH1\*\*\*\*\*\*\*\*\*\*\*\*/
GPIO_InitTypeDef GPIO_Initure;
\_\_HAL\_RCC\_TIM16\_CLK\_ENABLE(); //使能TIM16时钟
\_\_HAL\_RCC\_GPIOA\_CLK\_ENABLE(); //开启GPIOA时钟
GPIO_Initure.Pin = GPIO_PIN_6; //PB9
GPIO_Initure.Mode = GPIO_MODE_AF_PP; //复用输入
GPIO_Initure.Pull = GPIO_PULLUP; //上拉
GPIO_Initure.Speed = GPIO_SPEED_FREQ_HIGH; //高速
GPIO_Initure.Alternate = GPIO_AF5_TIM16;
HAL\_GPIO\_Init(GPIOA,&GPIO_Initure);
HAL\_NVIC\_SetPriority(TIM16_IRQn,2,0); //设置中断优先级,抢占优先级2,子优先级0
HAL\_NVIC\_EnableIRQ(TIM16_IRQn); //开启ITM16中断
}
}
3.2 定时器输入捕获
红外编码是由多个字节编码组成的,根据持续的高低电平时间不同,而形成的编码信号,此时可以通过定时器捕获来实现。
定时器输入捕获中断回调函数如下,红外信号基本都是低电平起,可先用下降沿捕获:
// ir\_inputCapture\_send.c
void HAL\_TIM\_IC\_CaptureCallback(TIM_HandleTypeDef \*htim)//捕获中断发生时执行
{
if(htim->Instance==TIM16)
{
if(READ\_IR\_GPIO()) //上升沿捕获
{
Dval = HAL\_TIM\_ReadCapturedValue(&TIM16_Handler, TIM_CHANNEL_1); //读取CCR1也可以清CC4IF标志位
TIM\_RESET\_CAPTUREPOLARITY(&TIM16_Handler, TIM_CHANNEL_1); //一定要先清除原来的设置!!
TIM\_SET\_CAPTUREPOLARITY(&TIM16_Handler, TIM_CHANNEL_1, TIM_ICPOLARITY_FALLING); //CC1P=1 设置为下降沿捕获
if(0 == irRun.receive.cnt) {
\_\_HAL\_TIM\_SET\_COUNTER(&TIM16_Handler,0); //清空定时器值
return ;
}
if(irRun.receive.cnt<(MAX_IR_LEARN_DATA_SIZE - 1)) { // 保存在数组中的 0 2 4 6 8 中
irRun.buf[irRun.receive.cnt++] = Dval;
}
else {
RcvRemoteFinish();
}
\_\_HAL\_TIM\_SET\_COUNTER(&TIM16_Handler,0); //清空定时器值
}
else //下降沿捕获
{
Dval = HAL\_TIM\_ReadCapturedValue(&TIM16_Handler, TIM_CHANNEL_1);
TIM\_RESET\_CAPTUREPOLARITY(&TIM16_Handler,TIM_CHANNEL_1);
TIM\_SET\_CAPTUREPOLARITY(&TIM16_Handler,TIM_CHANNEL_1,TIM_ICPOLARITY_RISING); //配置TIM16通道1上升沿捕获
//当前这一次,不计数,下一次上升沿才计数
if(0 == irRun.receive.cnt) {
\_\_HAL\_TIM\_SET\_COUNTER(&TIM16_Handler,0); //清空定时器值
return;
}
if(irRun.receive.cnt < (MAX_IR_LEARN_DATA_SIZE-1)) //1 3 5 7 9
{
irRun.buf[irRun.receive.cnt++] = Dval;
if(irRun.receive.cnt>=20) {
irRun.receive.dataComplete = 1;
}
}
else
{
RcvRemoteFinish();
}
\_\_HAL\_TIM\_SET\_COUNTER(&TIM16_Handler,0); //清空定时器 放最后
}
}
}
// ir\_inputCapture\_send.c
//60m定时器计时后溢出中断的回调函数:
void HAL\_TIM\_PeriodElapsedCallback(TIM_HandleTypeDef \*htim)
{
if(htim->Instance==TIM16) //定时器更新(溢出)中断回调函数 10ms溢出
{
if(irRun.receive.dataComplete) //至少已经收到了20个字节,才算接收到一帧信息
{
RcvRemoteFinish();
}
else {
irRun.receive.cnt = 0; //重新来过,此帧数据无效
}
}
}
// ir\_inputCapture\_send.c
/\* 当前红外遥控一帧结束。
触发条件:① 接收到的红外字节个数已经超过最大允许的长度 (HAL\_TIM\_IC\_CaptureCallback)
② 如上述的定时器计时后溢出中断的回调函数 (HAL\_TIM\_PeriodElapsedCallback)
\*/
static void RcvRemoteFinish(void)
{
//1. 先失能 避免重洗掉前面保存的一帧完整数据
TIM16\_Remote\_Disable();
//2. 重新设置下降沿捕获,以防上升沿捕获的
TIM\_SET\_CAPTUREPOLARITY(&TIM16_Handler, TIM_CHANNEL_1, TIM_ICPOLARITY_FALLING); //CC1P=1 设置为下降沿捕获
//3-1. 清零数据存在的标志
irRun.receive.dataComplete = 0; //先清零
//4-2. (多等待了60ms),不管如何都算完成了
irRun.receive.complete = 1; // irRun.receive.complete 为一帧接收的完整标志
irRun.receive.len = irRun.receive.cnt - 1; //一帧接收的最大长度,irRun.receive.cnt 多了1个
//清零接收长度 缓冲数据
irRun.receive.cnt = 0;
}
至此为止 数据保存在 irRun.buf 中, 个数为 irRun.receive.len 。
3.3 获取数据
具体见代码和详细的注释:
// 获取一帧数据在上层调用
// 返回值: 0, 没有任何按键按下
// 1 ,按下的按键键值.
// ir\_inputCapture\_send.c
u8 GetRemoteRcvBuf(uint16\_t \*buf, uint32\_t \*len, uint8\_t isRecord)
{
if(irRun.receive.complete && !irRun.receive.dataComplete) { //完成一帧的标记, 且现在没有正在捕获的信号
TIM\_SET\_CAPTUREPOLARITY(&TIM16_Handler, TIM_CHANNEL_1, TIM_ICPOLARITY_FALLING); //CC1P=1 设置为下降沿捕获
//最多拷贝MAX\_IR\_LEARN\_DATA\_SIZE个, 第二次保护,前有一次保护措施
if(irRun.receive.len >= MAX_IR_LEARN_DATA_SIZE-1)
irRun.receive.len = MAX_IR_LEARN_DATA_SIZE-1;
if(irRun.receive.len >= GetFuncLen() && GetFuncLen()>20 && isRecord) {
irRun.receive.len = GetFuncLen();
## 总结
至此,文章终于到了尾声。总结一下,我们谈论了简历制作过程中需要注意的以下三个部分,并分别给出了一些建议:
1. 技术能力:先写岗位所需能力,再写加分能力,不要写无关能力;
2. 项目经历:只写明星项目,描述遵循 STAR 法则;
3. 简历印象:简历遵循三大原则:清晰,简短,必要,要有的放矢,不要海投;
> 以及最后为大家准备的福利时间:简历模板+Java面试题+热门技术系列教程视频
![在这里插入图片描述](https://img-blog.csdnimg.cn/img_convert/b7d76945bb193f1c25a68df9e5ee86cc.webp?x-oss-process=image/format,png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/img_convert/11936895be0f437413979acdf320c971.webp?x-oss-process=image/format,png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/img_convert/65b610f6a400ca471a5a7db2c6d6487d.webp?x-oss-process=image/format,png)
> **本文已被[CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】](https://bbs.csdn.net/forums/4f45ff00ff254613a03fab5e56a57acb)收录**
**[需要这份系统化的资料的朋友,可以点击这里获取](https://bbs.csdn.net/forums/4f45ff00ff254613a03fab5e56a57acb)**
(img-HI2I2ub3-1715267539063)]
[外链图片转存中...(img-RQhqpYIZ-1715267539063)]
[外链图片转存中...(img-wE0KfXXn-1715267539063)]
> **本文已被[CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】](https://bbs.csdn.net/forums/4f45ff00ff254613a03fab5e56a57acb)收录**
**[需要这份系统化的资料的朋友,可以点击这里获取](https://bbs.csdn.net/forums/4f45ff00ff254613a03fab5e56a57acb)**