概述
一、二极管的单向导电性
二极管是电子电路中很常用的元器件,非常常见,二极管具有正向导通,反向截止的特性。
在二极管的正向端(正极)加正电压,负向端(负极)加负电压,二极管导通,有电流流过二极管。在二极管的正向端(正极)加负电压,负向端(负极)加正电压,二极管截止,没有电流流过二极管。这就是所说的二极管的单向导通特性。下面解释为什么二极管会单向导通。
二极管的单向导电性
二极管是由 PN 结组成的,即 P 型半导体和 N 型半导体,因此 PN 结的特性导致了二极管的单向导电特性。PN 结如下图所示。
在 P 型和 N 型半导体的交界面附近,由于 N 区的自由电子浓度大,于是带负电荷的自由电子会由 N 区向电子浓度低的 P 区扩散;扩散的结果使 PN 结中靠 P 区一侧带负电,靠 N 区一侧带正电,形成由 N 区指向 P 区的电场,即 PN 结内电场。内电场将阻碍多数载流子的继续扩散,又称为阻挡层。
PN 结详解
二极管的单向导电特性用途很广,到底是什么原因让电子如此听话呢?它的微观机理是什么呢?这里简单形象介绍一下。
假设有一块 P 型半导体(用黄色代表空穴多)和一块 N 型半导体(用绿色代表电子多),它们自然状态下分别都是电中性的,即不带电。如下图所示。
把它们结合在一起,就形成 PN 结。边界处 N 型半导体的电子自然就会跑去 P 型区填补空穴,留下失去电子而显正电的原子。相应 P 型区边界的原子由于得到电子而显负电,于是就在边界形成一个空间电荷区。为什么叫“空间电荷区”?是因为这些电荷是微观空间内无法移动的原子构成的。
空间电荷区形成一个内建电场,电场方向由 N 到 P,这个电场阻止了后面的电子继续过来填补空穴,因为这时 P 型区的负空间电荷是排斥电子的。电子和空穴的结合会越来越慢,最后达到平衡,相当于载流子耗尽了,所以空间电荷区也叫耗尽层。这时 PN 结整体还呈电中性,因为空间电荷有正有负互相抵消。如下图所示。
外加正向电压,电场方向由正到负,与内建电场相反,削弱了内建电场,所以二极管容易导通。绿色箭头表示电子流动方向,与电流定义的方向相反。如下图所示。
外加反向电压,电场方向与内建电场相同,增强了内建电场,所以二极管不容易导通。如下图所示。当然,不导通也不是绝对的,一般会有很小的漏电流。随着反向电压如果继续增大,可能造成二极管击穿而急剧漏电。
如下图,是二极管的电流电压曲线供参考。
如下图,形象的展示了不同方向二极管为什么能导通和不能导通,方便理解。
生活中单向导通的例子也不少,比如地铁进站口的单向闸机,也相当于二极管的效果:正向导通,反向不导通,如果硬要反向通过,可能就会因为太大力“反向击穿”破坏闸机了。 whaosoft aiot http://143ai.com
二、红外遥控信号自学习
这个红外遥控自学习的这个实验,用于来自己控制房子里如空调等红外遥控设备的自动化,NEC的标准到具体的产品上可能就被厂家定义为不一样了,所以自学习就应该是接收到什么就发送什么,不用管内容是什么!
2 硬件实现原理
由上述原理图可知,当IE为高电平时发送红外光,为低电平时不发送红外光。
在NEC协议中,信息传输是基于38K载波,也就是说红外线是以载波的方式传递。
发送波形如下图所示:
NEC协议规定:
-
发送协议数据“0” = 发送载波560us + 不发送载波560us
-
发送协议数据“1” = 发送载波560us+ 不发送载波1680us
-
发送引导码 = 发送载波9000us + 不发送载波4500us
在红外接收端,如果接收到红外38K载波,则IR输出为低电平,如果不是载波包括固定低电平和固定高电平则输出高电平。在IR端接收的信号如下所示:
3 软件实现自学习
设计原理:
1、 根据接收波形记录电平和电平持续时间,以便于发送。
2、电平记录采用定时器捕获功能,从下降沿接收引导信号开始,每触发一次改变触发方式,从而使每个电平变化都能捕获到。
源码实现如下:
定时器捕获初始化设置(CubeMax软件自动配置生成):
void MX_TIM4_Init(void)
{
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_IC_InitTypeDef sConfigIC = {0};
htim4.Instance = TIM4;
htim4.Init.Prescaler = 71;
htim4.Init.CounterMode = TIM_COUNTERMODE_UP;
htim4.Init.Period = 10000;
htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim4) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim4, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
if (HAL_TIM_IC_Init(&htim4) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim4, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
sConfigIC.ICFilter = 0;
if (HAL_TIM_IC_ConfigChannel(&htim4, &sConfigIC, TIM_CHANNEL_4) != HAL_OK)
{
Error_Handler();
}
}
定时器捕获中断回调处理:
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_4)
{
if(TIM4->CCER & (TIM_CCER_CC4P)) //下降沿触发
{
TIM4->CCER &= ~(TIM_CCER_CC4P); //切换
gu8BitVal = 1;
}
else //上升沿触发
{
TIM4->CCER |= TIM_CCER_CC4P; //切换
gu8BitVal = 0;
}
if(gsInfrared.State == NONE_STATE)
{
gsInfrared.State = RECV_STATE;
}
else if(gsInfrared.State == RECV_STATE)
{
NowTimCnt = HAL_TIM_ReadCapturedValue(&htim4, TIM_CHANNEL_4);
gsInfrared.KeepTime[gsInfrared.SampleCount] = Round(NowTimCnt);
gsInfrared.BitValue[gsInfrared.SampleCount ++] = gu8BitVal;
}
TIM4->CNT = 0;
}
}
3、设置的定时器溢出时间为10ms,如果10毫秒内不再接收电平变化则默认接收结束,设置结束标志。
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim == &htim4)
{
if(gsInfrared.State == RECV_STATE)
{
gsInfrared.State = END_STATE;
}
}
}
至此,实现了红外遥控的学习功能,获得的记录数据为记录长度和电平信号数组与电平信号维持的时间数组。
4、发送实现
设置定时器输出38KPWM信号,在记录电平为0是输出记录时间的38K载波信号,如果为1则不输出载波,实现如下:
PWM生成设置,CubeMax自动配置生成如下代码:
void MX_TIM5_Init(void)
{
TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_OC_InitTypeDef sConfigOC = {0};
htim5.Instance = TIM5;
htim5.Init.Prescaler = 0;
htim5.Init.CounterMode = TIM_COUNTERMODE_UP;
htim5.Init.Period = 1896;
htim5.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim5.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_PWM_Init(&htim5) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim5, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 0;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
if (HAL_TIM_PWM_ConfigChannel(&htim5, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
{
Error_Handler();
}
HAL_TIM_MspPostInit(&htim5);
}
发送实现,注意点就是记录为0时发载波,记录为1时不发载波:
void InfraredSend(void)
{
uint16_t Count = 0;
while(Count < gsInfrared.SampleCount && gsInfrared.State == END_STATE)
{
if(gsInfrared.BitValue[Count] == 0)
{
TIM5->CCR2 = 948;
delay_us(gsInfrared.KeepTime[Count]);
TIM5->CCR2 = 0;
}
else
{
TIM5->CCR2 = 0;
delay_us(gsInfrared.KeepTime[Count]);
TIM5->CCR2 = 0;
}
Count ++;
}
delay_us(20000);
}
往PWM比较寄存器设置948即为设置38KPWM波,也可在初始化时固定948,在此函数内启停定时器即可;
至此,自学习功能的全部思路已实现,通过对各个不同类型的红外遥控进行功能测试,均成功。
PS:查看很多资料发现很多红外解码未判断低电平时间,个人感觉不是很好,应该是不仅高电平时间得符合,低电平时间也应该符合。
自己写了一个小函数验证了一下,这个函数只是验证,未经仔细推敲,还可优化,仅供参考这一思想。
误差设计:±200us(拍脑袋值)
void InFraredDataDeal(void)
{
uint32_t DataBuff = 0;
uint16_t Count = 0;
if(gsInfrared.State == END_STATE)
{
gsInfraredData.State = 0;
do
{
switch(gsInfraredData.State)
{
case 0: //引导码识别
{
if(gsInfrared.KeepTime[0] >= 8800 && gsInfrared.KeepTime[0] <= 9200 && gsInfrared.BitValue[0] == 0)
{
if(gsInfrared.KeepTime[1] >= 4300 && gsInfrared.KeepTime[1] <= 4700 && gsInfrared.BitValue[1] == 1)
{
if(gsInfrared.KeepTime[2] >= 360 && gsInfrared.KeepTime[2] <= 760 && gsInfrared.BitValue[2] == 0)
{
Count = 3;
gsInfraredData.State = 1;
}
}
else if(gsInfrared.KeepTime[1] >= 2300 && gsInfrared.KeepTime[1] <= 2700 && gsInfrared.BitValue[1] == 1)
{
if(gsInfrared.KeepTime[2] >= 360 && gsInfrared.KeepTime[2] <= 760 && gsInfrared.BitValue[2] == 0)
{
gsInfraredData.ReDataCount ++;
gsInfraredData.State = 3;
}
}
else
{
gsInfraredData.State = 3;
}
}
else
{
gsInfraredData.State = 3;
}
}
break;
case 1: //数据解析
{
if(gsInfrared.KeepTime[Count + 1] >= 360 && gsInfrared.KeepTime[Count + 1] <= 760 && gsInfrared.BitValue[Count + 1] == 0)
{
if(gsInfrared.BitValue[Count] == 1)
{
if(gsInfrared.KeepTime[Count] >= 1480 && gsInfrared.KeepTime[Count] <= 1880)
{
DataBuff <<= 1;
DataBuff |= 1;
}
else if(gsInfrared.KeepTime[Count] >= 360 && gsInfrared.KeepTime[Count] <= 760 && gsInfrared.BitValue[Count] == 1)
{
DataBuff <<= 1;
DataBuff |= 0;
}
else
{
gsInfraredData.State = 3;
}
}
}
if(Count < gsInfrared.SampleCount)
{
Count += 2;
}
else
{
gsInfraredData.State = 2;
}
}
break;
case 2: //成功解析
{
gsInfraredData.Data = DataBuff;
gsInfraredData.State = 3;
}
break;
default:
{
gsInfraredData.State = 3; //解析结束
}
break;
}
}
while(gsInfraredData.State != 3);
gsInfrared.State = NONE_STATE;
gsInfrared.SampleCount = 0;
}
}
解析的话一般高位在前,所以左移,经测试帧格式为:引导码+用户码+用户码反码+命令码+命令码反码,能成功解析数据!解析的话根据具体协议,具体分析。
最后
以上就是危机白猫为你收集整理的嵌入式分享合集55的全部内容,希望文章能够帮你解决嵌入式分享合集55所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复