OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 5922|回复: 13

遥控红外发射程序的优化

[复制链接]

4

主题

52

帖子

1

精华

中级会员

Rank: 3Rank: 3

积分
472
金钱
472
注册时间
2016-2-22
在线时间
85 小时
发表于 2017-1-20 11:26:54 | 显示全部楼层 |阅读模式
正在做红外遥控解码分析的程序,想着把之前用延时等待方式的红外发送代码优化下,能做到开始发送后不用管,主程序能处理其它工作。
要满足这个要求就要先生成整个红外时间序列,以NEC为例IR数组为9000,4500,560,560,560,1690...(第一位高电平,第二位低电平以此类推), 然后由中断来按时间序列自动发送。
上面的数组时间是us单位,这样除了38k PWM定时器外还需要另一个定时器来处理时间,并且若时间大于65000us则超了16位会更烦。所以我这里不用时间单位而用脉冲数做单位,38k的时间周期是26us,9000us转到脉冲数是346,现在就能只用一个定时器产生PWM,并计算溢出次数是否大于346就能实现计时了。
完整代码如下,以NEC为例连续发送两个红外信号,在MDK中模拟的逻辑分析中看了波形没问题。这样改了后集中了编码处理,使结构非常清晰,要转成其它的编码也会很简单。

#include "stm32f10x.h"

#define NEC_HDR_MARK    9000
#define NEC_HDR_SPACE   4500
#define NEC_BIT_MARK     560
#define NEC_ONE_SPACE   1690
#define NEC_ZERO_SPACE   560
#define NEC_STOP_SPACE 40000
#define NEC_RPT_SPACE   2250
#define NEC_RPT_SPACE1 98000
#define NEC_38K_T      26     //38k周期=26us

#define LOW_BIT 0x0
#define HIGH_BIT 0x1
#define START_BIT 0x2
#define STOP_BIT 0x3
#define RPT_BIT 0x4

uint16_t ir_nec_date[200];
uint8_t offset =0;
uint8_t lenth =0;
int start=0;
int times=0;

//使用SetCompare修改ccr,脉冲计数方式定时
void pwm_init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE );
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;        
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;   
GPIO_Init(GPIOA, &GPIO_InitStructure);
TIM_TimeBaseStructure.TIM_Period = 1895;  //38K
TIM_TimeBaseStructure.TIM_Prescaler = 0;   
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;               
TIM_OCInitStructure.TIM_Pulse = 0;   // 初始低电平,高电平为500,占空比=500/(1895-500)
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;         
TIM_OC4Init(TIM2, &TIM_OCInitStructure);
TIM_OC4PreloadConfig(TIM2, TIM_OCPreload_Enable);
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
TIM_ARRPreloadConfig(TIM2, ENABLE);
TIM_ITConfig( TIM2,TIM_IT_Update,ENABLE);//允许更新中断
TIM_Cmd(TIM2, ENABLE); //使能定时器
}

void TIM2_IRQHandler(void)
{
if(TIM_GetITStatus(TIM2,TIM_IT_Update)!=RESET)
{
  TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
  if(start)
  {
   if (offset%2==0)
    TIM_SetCompare4(TIM2,500);
   else
    TIM_SetCompare4(TIM2,0);
   times++;
   if (times>=ir_nec_date[offset])
   {
    times=0;
    offset++;
    if(offset>lenth)
    {
     start=0;       //发送完成,置标记,可以开始新的发送
     TIM_SetCompare4(TIM2,0);
    }
   }
  }
}
}

void ir_nec_get_bit(uint8_t ir_bit)
{
switch( ir_bit)
{
  case START_BIT:
   ir_nec_date[offset++]=NEC_HDR_MARK/NEC_38K_T;
   ir_nec_date[offset++]=NEC_HDR_SPACE/NEC_38K_T;
   break;
  case STOP_BIT:
   ir_nec_date[offset++]=NEC_BIT_MARK/NEC_38K_T;
   ir_nec_date[offset++]=NEC_STOP_SPACE/NEC_38K_T;
   break;
  case HIGH_BIT:
   ir_nec_date[offset++]=NEC_BIT_MARK/NEC_38K_T;
   ir_nec_date[offset++]=NEC_ONE_SPACE/NEC_38K_T;
   break;
  case LOW_BIT:
   ir_nec_date[offset++]=NEC_BIT_MARK/NEC_38K_T;
   ir_nec_date[offset++]=NEC_ZERO_SPACE/NEC_38K_T;
   break;
  case RPT_BIT:
   ir_nec_date[offset++]=NEC_HDR_MARK/NEC_38K_T;
   ir_nec_date[offset++]=NEC_RPT_SPACE/NEC_38K_T;
   ir_nec_date[offset++]=NEC_BIT_MARK/NEC_38K_T;
   ir_nec_date[offset++]=NEC_RPT_SPACE1/NEC_38K_T;
   break;
}
}

void ir_nec_get_data(uint8_t address,uint8_t command,uint8_t rpt) //参数:地址码,命令码,重复次数
{
int i;
offset =0;
ir_nec_get_bit(START_BIT);
for (i=0;i<8;i++)
  ir_nec_get_bit(((address>>i)&0x01));
address=~address;
for (i=0;i<8;i++)
  ir_nec_get_bit(((address>>i)&0x01));
for (i=0;i<8;i++)
  ir_nec_get_bit(((command>>i)&0x01));
command=~command;
for (i=0;i<8;i++)
  ir_nec_get_bit(((command>>i)&0x01));
ir_nec_get_bit(STOP_BIT);
for (i=0;i<rpt;i++)
  ir_nec_get_bit(RPT_BIT);

lenth =offset;
offset=0;
times=0;
}

int main ()
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
pwm_init();
ir_nec_get_data(0,0,1); //生成红外序列数组
start=1; //置标志位开始发送

while (start==1); //再次发送要生成数组前,需确认上次发送是否已完成
ir_nec_get_data(0x12,0x34,2);
  start=1;
   
while (1)
{  
}
}

无标题.png

main.rar

1.55 KB, 下载次数: 678

代码

正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

120

主题

7878

帖子

13

精华

资深版主

Rank: 8Rank: 8

积分
12012
金钱
12012
注册时间
2013-9-10
在线时间
427 小时
发表于 2017-1-20 12:32:45 | 显示全部楼层
回复 支持 反对

使用道具 举报

1

主题

19

帖子

0

精华

初级会员

Rank: 2

积分
151
金钱
151
注册时间
2012-10-13
在线时间
50 小时
发表于 2017-3-22 10:54:02 | 显示全部楼层
经测试可以,改了下代码使得可以用原子的板子进行接收,群主的例子是从低位先发送,需改成从高位先发送。另外需要发送结束码,否则收不到数据。我去掉了重复码。
得之我幸,失只我命!
回复 支持 反对

使用道具 举报

4

主题

52

帖子

1

精华

中级会员

Rank: 3Rank: 3

积分
472
金钱
472
注册时间
2016-2-22
在线时间
85 小时
 楼主| 发表于 2017-3-23 20:43:03 | 显示全部楼层
yihui184 发表于 2017-3-22 10:54
经测试可以,改了下代码使得可以用原子的板子进行接收,群主的例子是从低位先发送,需改成从高位先发送。另 ...

在单位里没事的时候改的,只用了模拟仿真看了下图形,没上机测过,应该会有问题的,多谢帮忙测试 !
回复 支持 反对

使用道具 举报

5

主题

46

帖子

0

精华

初级会员

Rank: 2

积分
162
金钱
162
注册时间
2016-7-28
在线时间
41 小时
发表于 2017-12-6 17:44:23 | 显示全部楼层
感谢分享,用原子的接收器实验成功接收并显示数值
回复 支持 反对

使用道具 举报

6

主题

28

帖子

0

精华

初级会员

Rank: 2

积分
141
金钱
141
注册时间
2017-6-28
在线时间
44 小时
发表于 2018-4-1 13:31:43 | 显示全部楼层
yihui184 发表于 2017-3-22 10:54
经测试可以,改了下代码使得可以用原子的板子进行接收,群主的例子是从低位先发送,需改成从高位先发送。另 ...

楼主可以分享一下代码吗?
回复 支持 反对

使用道具 举报

6

主题

28

帖子

0

精华

初级会员

Rank: 2

积分
141
金钱
141
注册时间
2017-6-28
在线时间
44 小时
发表于 2018-4-1 13:32:04 | 显示全部楼层
Brantim 发表于 2017-12-6 17:44
感谢分享,用原子的接收器实验成功接收并显示数值

可以分享一下代码吗?
回复 支持 反对

使用道具 举报

5

主题

46

帖子

0

精华

初级会员

Rank: 2

积分
162
金钱
162
注册时间
2016-7-28
在线时间
41 小时
发表于 2018-6-12 11:18:50 | 显示全部楼层
郁郁葱葱 发表于 2018-4-1 13:32
可以分享一下代码吗?

楼主不是已经写好代码了吗?直接用就可以
回复 支持 反对

使用道具 举报

1

主题

83

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3546
金钱
3546
注册时间
2017-7-10
在线时间
389 小时
发表于 2018-7-17 17:02:15 | 显示全部楼层
思路很好啊,谢谢
回复 支持 反对

使用道具 举报

4

主题

14

帖子

0

精华

新手上路

积分
41
金钱
41
注册时间
2019-8-8
在线时间
9 小时
发表于 2019-9-9 16:35:43 | 显示全部楼层
楼主你好,为什么我发现你的波形的1,0 逻辑是反过来的,就是一开始的9ms不是应该是低电平和4.5毫秒的高电平吗,为什么你的是9ms高电平啊
回复 支持 反对

使用道具 举报

4

主题

14

帖子

0

精华

新手上路

积分
41
金钱
41
注册时间
2019-8-8
在线时间
9 小时
发表于 2019-9-9 16:39:04 | 显示全部楼层
本帖最后由 呱呱呱呱 于 2019-9-9 17:30 编辑
yihui184 发表于 2017-3-22 10:54
经测试可以,改了下代码使得可以用原子的板子进行接收,群主的例子是从低位先发送,需改成从高位先发送。另 ...

你好,这个代码按照楼主的从低位发送不可以吗?还有怎么加上结束码,我今天试验的时候,发现手机拍二极管一直不亮,还有一个问题就是,同步码不是9ms低电平和4.5ms高电平吗,这个为什么感觉是反过来的,大哥帮帮新手(已明白为什么取反了,因为发送端和接收端相反,其他还有疑惑)
回复 支持 反对

使用道具 举报

4

主题

14

帖子

0

精华

新手上路

积分
41
金钱
41
注册时间
2019-8-8
在线时间
9 小时
发表于 2019-9-10 11:41:12 | 显示全部楼层
Brantim 发表于 2017-12-6 17:44
感谢分享,用原子的接收器实验成功接收并显示数值

你好,请问一下你是将楼主的代码做了怎样的修改才可以的吗,为什么我不一直不成功呢
回复 支持 反对

使用道具 举报

0

主题

5

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
275
金钱
275
注册时间
2019-3-19
在线时间
111 小时
发表于 2019-10-15 20:31:36 | 显示全部楼层
最近也在看红外发射的程序,学习一下
回复 支持 反对

使用道具 举报

4

主题

15

帖子

0

精华

初级会员

Rank: 2

积分
146
金钱
146
注册时间
2019-9-14
在线时间
24 小时
发表于 2019-11-22 01:33:30 来自手机 | 显示全部楼层
呱呱呱呱 发表于 2019-9-10 11:41
你好,请问一下你是将楼主的代码做了怎样的修改才可以的吗,为什么我不一直不成功呢

现在成功了吗
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-5-25 13:00

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表