我是靠谱客的博主 可爱芝麻,这篇文章主要介绍STM32 通过定时器产生PPM信号,现在分享给大家,希望可以做个参考。

标题STM32 通过定时器产生PPM信号

  • 说明:
    该代码基于STM32F103VET6 和STD标准库实现。若需要在其他单片平台使用需要调整IO,和定时器,底层代码。
    定时器要达到us级定时。
    实现原理是,将ppm 每个通道的高低电平脉宽时间,存入一个数组中。如PPM有用通道8个,分解高低电平脉宽时间为16个时间数据。
    通过定时器依次执行每个时间值。在定时执行时,根据信号特征改变IO电平,以达到输出PPM信号的目的。

  • 底层c文件

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
void ppm_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 ; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //ÍÆÍìÊä³ö50MHZ GPIO_Init(GPIOA, &GPIO_InitStructure); } /** * @brief 基本定时器初始化,用于非阻塞延时用. * @param None * @retval None */ void Timer_PPM_Tim5_Init(void) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE); //时钟使能 TIM_TimeBaseStructure.TIM_Period = 999; //499 == 5 ms 中断一次 TIM_TimeBaseStructure.TIM_Prescaler = 71; // TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure); TIM_ClearFlag(TIM5, TIM_FLAG_Update); // TIM_ARRPreloadConfig(TIM7, DISABLE); TIM_ITConfig(TIM5, TIM_IT_Update, ENABLE); TIM_Cmd(TIM5, ENABLE); } u16 ppm_value = 0; void Timer_PPM_Tim5_Time(u16 *timer) { ppm_value = *timer; TIM_SetAutoreload(TIM5,*timer); } void Timer_PPM_Tim5_Start(void) { TIM_ClearFlag(TIM5, TIM_FLAG_Update); TIM_ITConfig(TIM5, TIM_IT_Update, ENABLE); TIM_Cmd(TIM5, ENABLE); } void Timer_PPM_Tim5_Stop(void) { TIM_ITConfig(TIM5, TIM_IT_Update, DISABLE); TIM_Cmd(TIM5, DISABLE); } void TIM_PPM_Init(void) { ppm_GPIO_Init(); Timer_PPM_Tim5_Init(); } void TIM5_IRQHandler(void) { if (TIM_GetITStatus(TIM5, TIM_IT_Update) != RESET) { ppm_out_process(); TIM_ClearITPendingBit(TIM5, TIM_FLAG_Update); } }
  • *h文件
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
#ifndef __TIM_PPM_H #define __TIM_PPM_H #define PPM_PIN PAout(0) void TIM_PPM_Init(void); void Timer_PPM_Tim5_Start(void); void Timer_PPM_Tim5_Stop(void); void Timer_PPM_Tim5_Time(u16 *timer); #endif
  • 中间层c代码
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
/******************************************************************************* * ***************************************************************************** * 该部分功能实现需要开起一个1us中断一次的定时器,ppm_out_process()函数放在定时 * 中断函数里面。 * 主程序调用该函数ppm_MarkProcess()实现ppm数据的更新 * 实现原理将:PPM理论上可以容纳10通道,但是有起始头等操作。所以占用一个通道的 * 处理。最大也就容纳9个通道。根据通道的上升沿和下降沿找到20个标志时间点做跳变 * 处理,输出PPM信号. * **************************************************************************** * ****************************************************************************/ #include "includes.h" #define PPM_OUT_L 0 #define PPM_OUT_H 1 #define PPM_CH_NUB 8 //ppm通道数 #define PPM_FLAG_SPOT_NUB 18 //(PPM_CH_NUB *2 + 2) #define PPM_CYCLE_TIME 20000 //us //50hz #define PPM_LOW_TIME 400 //us #define LOCK 1 #define UNLOCK 0 u8 Lock = UNLOCK; u16 ppm_data_flag[PPM_FLAG_SPOT_NUB]; PPM_Struct PPM = { ppm_init, ppm_out_process, //定时器回调函数 ppm_MarkProcess, NULL, NULL, }; PPM_Bottom_Struct PPM_Bottom = { &PPM_PIN, TIM_PPM_Init, Timer_PPM_Tim5_Time, Timer_PPM_Tim5_Start, Timer_PPM_Tim5_Stop, }; //ppm数据初始化 void ppm_init(void) { u8 i; for (i = 0; i < PPM_CH_NUB + 1; i ++) { ppm_data_flag[i * 2 + 1] = PPM_LOW_TIME; } PPM_Bottom.Init(); *(PPM_Bottom.PPM_OUT_PIN) = PPM_OUT_L; Delay_ms(1000); } //ppm输出处理 void ppm_out_process(void) { static u8 state = 0; //TIM_SetAutoreload(TIM5,ppm_data_flag[state]); PPM_Bottom.Time(&ppm_data_flag[state]); *(PPM_Bottom.PPM_OUT_PIN) = ~*(PPM_Bottom.PPM_OUT_PIN); state += 1; state %= PPM_FLAG_SPOT_NUB; } //ppm数据输入填充处理 void ppm_MarkProcess(u16 *buf) { u16 *p = &ppm_data_flag[2]; //u32 cycleTime_flag_time = PPM_HERAD_TIME; u32 cycleTime_flag_time = 0; u8 i; Lock = LOCK; for(i = 0; i < PPM_CH_NUB; i ++) { cycleTime_flag_time += buf[i]; p[i * 2] = buf[i] - PPM_LOW_TIME; } ppm_data_flag[0] = PPM_CYCLE_TIME - cycleTime_flag_time - PPM_LOW_TIME; Lock = UNLOCK; p = NULL; }
  • *h
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#ifndef __PPM_H_ #define __PPM_H_ //ppm 对外调用接口 typedef struct { void (*Init)(void); void (*Out_process)(void); void (*MarkProcess)(u16 *buf); void (*Start)(void); void (*Stop)(void); }PPM_Struct; //ppm 底层接口 typedef struct { volatile unsigned long *PPM_OUT_PIN; void (*Init)(void); void (*Time)(u16 *timer); void (*Start)(void); void (*Stop)(void); }PPM_Bottom_Struct; extern PPM_Struct PPM; void ppm_init(void); void ppm_out_process(void); void ppm_MarkProcess(u16 *buf); #endif

最后

以上就是可爱芝麻最近收集整理的关于STM32 通过定时器产生PPM信号的全部内容,更多相关STM32内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(78)

评论列表共有 0 条评论

立即
投稿
返回
顶部