STM32
直播中

切克切克闹

11年用户 467经验值
私信 关注
[问答]

如何去实现一种基于STM32的红外万能遥控器设计呢

如何去实现一种基于STM32的红外***?有哪些操作步骤?

回帖(2)

李平

2021-11-17 09:52:05
一、概述
  一直想自己实现一个类似于万能遥控的功能,最近借着嵌入式课设的机会终于完成了这个项目,目前已经完成了验收,将工程源码全部开源Github,希望能对大家有所帮助。
  实现的功能
  学习、存储和发射标准NEC格式的红外信息,如机顶盒,少数电视
  学习、存储和发射非标准格式的红外信息,如风扇,空调
  展示NEC格式解码后的数据(二进制和十进制展示)
  展示非标准格式的波形数据(包括高低电平及其持续时间)
  参考文档
  详解红外遥控器编码解码原理!
  Github Infrared Universal Control
  基于STM32的红外遥控重点解析
  格力空调遥控器红外编码透析(长码)
  二、项目的逻辑
  使用单片机遥控器控制demo,OLED屏幕显示提示信息和数据,使用单片机遥控机进行功能选择,学习完成后,也是要单片机遥控器控制demo发射学习到的信息实现控制其他设备的功能,所以就能够实现使用一个单片机遥控器控制所有红外家电的目标。
  因为单片机遥控器按键数量有限,为了能够控制更多设备,这个项目实现了分区的功能,在进入英国威廉希尔公司网站 后,可以按1选择不同的区,每个区对应flash里面不同的起始地址,在学习存储和发射红外信息时相同的按键值对应的存储空间就会不同,从而实现按键的复用。
  简单来说:使用单片机遥控器来控制设备发出可以控制其它家电的红外信号。
  三、硬件
  主控
  STM32F103xx(flash最好大于等于256k,方便存储数据,该项目使用的是STM32F103RCT6最小系统板)
    接线方式
  OLED
  电源3.3v
  SCL -》 PB6
  SDA -》 PB7
  红外接收器
  电源3.3v
  DAT -》 PB9
  红外发射器
  VCC -》 3V3
  GND -》 PC2(使用PC2引脚输出高低电平实现对发射器的开关控制)
  DAT -》 PA0
  四、代码
  结构
  Template(工程目录)
  |- USER
  |- main.c (主函数文件)
  |- SYSTEM
  |- delay.c (延时函数,来自于STM32F4的库,F1的延时函数时间不准!!!)
  |- HARDWARE
  |- oled.c (OLED驱动)
  |- remote.c (红外接收器驱动)
  |- pwm.c (波形产生驱动,用于产生38KHz 方波)
  |- irsend.c (红外发射器驱动)
  |- stmflash.c (flash存储驱动)
  |- remote_save.c (在stmflash.c的基础上编写的便于存储红外数据的存储驱动)
  其他文件和目录均来自于正点原子库函数模版
  驱动函数 xx.c 和 xx.h 一 一对应,接口写在xx.h中,具体实现在xx.c中实现,本文主要介绍逻辑,以h文件为主,详细代码请看Github。
  Main函数
  #include “oled.h”
  #include “remote.h”
  #include “pwm.h”
  #include “irsend.h”
  #include “usart.h”
  #include “delay.h”
  #include “remote_save.h”
  #include “guet.h”
  //主要的函数模块
  void showData(u32 data); //显示数据信息
  void data_Init(void); //红外数据数组初始化
  void ShowSquareWave_Init(void); //初始化波形数组
  void SetPart(void); //设置区号1-9 主要是为了扩大设备可用性,用不同区号相同按键实现不同的功能(按键的复用)
  int GetPart(void); //得到区号,在英国威廉希尔公司网站 显示,便于用户区分
  void SendLearn(void); //学习/发送函数
  void Delete(void); //删除数据函数
  void ShowData(void); //展示输入信号信息函数
  int key; //用于记录用户按下的按键或者数据信息
  u16 data[350]; //红外数据数组,存储波形时间数据
  u16 addr = 0; //偏移量
  unsigned char show[128 * 2] = {0}; //波形显示存储数组
  int main()
  {
  //初始化部分
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
  uart_init(115200);
  delay_init(72);
  OLED_IIC_Init(); //初始化OLED IIC
  Initial_M096128x64_ssd1306(); //OLED初始化
  OLED_Fill_picture(0x00); //清屏
  Remote_Init();
  TIM2_PWM_Init(1895,0);
  IR_SendPort_Init();
  ShowSquareWave_Init();
  //显示欢迎页
  OLED_Picture_Part(guet, 0, 64, 0, 8);
  OLED_ShowStr(10, 1, “GUET”);
  OLED_ShowStr(8, 3, “Welcome”);
  Remote_Num(); //暂停
  //显示英国威廉希尔公司网站 功能提示信息
  while (1)
  {
  OLED_Fill_picture(0x00); //清屏
  OLED_ShowStr(0, 0, “1.SetPart( )”);
  OLED_ShowNum(10, 0, GetPart(), 1);
  OLED_ShowStr(0, 1, “2.Send/Learn”);
  OLED_ShowStr(0, 2, “3.Delete”);
  OLED_ShowStr(0, 3, “4.ShowData”);
  switch (Remote_Num()) //输入数字进入相应的功能模块
  {
  case 1:
  SetPart();
  break;
  case 2:
  SendLearn();
  break;
  case 3:
  Delete();
  break;
  case 4:
  ShowData();
  break;
  }
  }
  }
  mian函数展示了项目的基础控制逻辑:上电后显示欢迎页(校徽),单片机遥控器按下任意按键进入主菜单,菜单样式:
  | 1.SetPart(1) -》 设置分区
  | 2.Send/Learn -》 进入发射、学习模式
  | 3.Delete -》 进入删除模式(删除存储的红外数据)
  | 4.ShowData -》 进入展示模式(显示NEC的解码数据或非标准数据的波形)
  按下对应数字进入相应功能。
  子模式函数:
  /**
  * OLED显示32位数据的信息(左边二进制,右边十进制)
  *
  * @param data 32位数据
  */
  void showData(u32 data)
  {
  OLED_Fill_picture(0x00); //清屏
  OLED_ShowBite(0, 0, data 》》 24);
  OLED_ShowNum(10, 0, data 》》 24, 3);
  OLED_ShowBite(0, 1, data 》》 16);
  OLED_ShowNum(10, 1, (data 》》 16) % 256, 3);
  OLED_ShowBite(0, 2, data 》》 8);
  OLED_ShowNum(10, 2, (data 》》 8) % 256, 3);
  OLED_ShowBite(0, 3, data);
  OLED_ShowNum(10, 3, data % 256, 3);
  }
  /**
  * 红外数据数组初始化
  */
  void data_Init(void)
  {
  int i;
  for(i = 0; i 《 350; i++)
  {
  data[i] = 0;
  }
  }
  /**
  * 设置区号1-9 主要是为了扩大设备可用性,用不同区号相同按键实现不同的功能(按键的复用)
  */
  void SetPart(void)
  {
  OLED_Fill_picture(0x00); //清屏
  OLED_ShowStr(0, 0, “SetPart:0-9”);
  while (1)
  {
  key = Remote_Num();
  if (key == POWER)
  break;
  else if (key 》= 1 && key 《= 9)
  {
  addr = (key - 1) * 20;
  break;
  }
  }
  }
  /**
  * 得到区号,在英国威廉希尔公司网站 显示,便于用户区分
  */
  int GetPart(void)
  {
  return addr / 20 + 1;
  }
  /**
  * 数字学习模式
  */
  void DigitalLearn(void)
  {
  while (1)
  {
  u32 get;
  OLED_Fill_picture(0x00); //清屏
  OLED_ShowStr(0, 0, “Select key!”);
  key = Remote_Num();
  if (key == POWER)
  break;
  OLED_ShowStr(0, 1, “Getting.。.”);
  get = Remote_GetData();
  showData(get);
  data[0] = (u16)get;
  data[1] = (u16)(get 》》 16);
  SaveData(addr + key, 0, data, 2);
  delay_ms(100);
  }
  }
  /**
  * 模拟学习模式
  */
  void AnalogLearn(void)
  {
  while (1)
  {
  int a;
  OLED_Fill_picture(0x00); //清屏
  OLED_ShowStr(0, 0, “Select key!”);
  key = Remote_Num();
  if (key == POWER)
  break;
  OLED_ShowStr(0, 1, “Input after 2s!”);
  delay_ms(1000);
  OLED_ShowStr(0, 1, “Input after 1s!”);
  delay_ms(1000);
  OLED_Clean(1);
  Re_Record_ON();
  OLED_ShowStr(5, 1, “Input!”);
  delay_ms(1500);
  OLED_ShowStr(5, 2, “OK!”);
  a = Re_Record_OFF();
  OLED_ShowNum(9, 2, a, 4);
  SaveData(addr + key, 1, Re_Record_Get(), a);
  delay_ms(400);
  }
  }
  /**
  * 学习/发送函数
  */
  void SendLearn(void)
  {
  int dot = 0; //用了记录上次执行了哪个操作,确定是否需要清空屏幕
  while (1)
  {
  if (dot == 0)
  OLED_Fill_picture(0x00); //清屏
  else if (dot == 1)
  OLED_Clean(3);
  else if (dot == 2)
  OLED_Clean(0);
  OLED_ShowStr(0, 0, “Mode:learn”);
  OLED_ShowStr(0, 1, “POWER:exit”);
  OLED_ShowStr(0, 2, “Other:send”);
  dot = 0;
  key = Remote_Num();
  if (key == POWER)
  break;
  if (key == MODE)
  {
  // 学习模式
  while (1)
  {// 选择学习模式
  OLED_Fill_picture(0x00); //清屏
  OLED_ShowStr(0, 0, “Learn Mode:”);
  OLED_ShowStr(0, 1, “1.Digital”);
  OLED_ShowStr(0, 2, “2.Analog”);
  key = Remote_Num();
  if (key == POWER)
  break;
  else if (key == 1)
  {// 数字模式
  DigitalLearn();
  }
  else if (key == 2)
  {// 模拟模式
  AnalogLearn();
  }
  }
  }
  else
  {
  // 发送模式
  int sta;
  data_Init();
  sta = GetData(addr + key, data);
  if (sta != -1)
  {
  OLED_ShowStr(2, 3, “SEND!”);
  delay_ms(100);
  Remote_OFF();
  TR_SendTimeData(data, sta);
  Remote_ON();
  delay_ms(200);
  dot = 1;
  }
  else //未读取到数据
  {
  OLED_Fill_picture(0x00); //清屏
  OLED_ShowStr(0, 0, “Don‘t have data!”);
  delay_ms(300);
  dot = 2;
  }
  }
  }
  }
  /**
  * 删除数据函数
  */
  void Delete(void) //删除数据函数
  {
  OLED_Fill_picture(0x00); //清屏
  while (1)
  {
  OLED_Clean(3);
  OLED_ShowStr(0, 0, “Mode:del all”);
  OLED_ShowStr(0, 1, “POWER:exit”);
  OLED_ShowStr(0, 2, “Other:del one”);
  key = Remote_Num();
  if (key == POWER)
  break;
  if (key == MODE)
  {
  DelPartData(addr);
  OLED_ShowStr(0, 3, “del all success!”);
  delay_ms(300);
  }
  else
  {
  
举报

张忠雨

2021-11-17 09:52:10
DelData(addr + key);
  OLED_ShowStr(0, 3, “del one success!”);
  delay_ms(300);
  }
  }
  }
  /**
  * 初始化波形数组
  */
  void ShowSquareWave_Init(void)
  {
  int i, j;
  show[0] = 0xfe;
  show[1] = 0xfe;
  show[128 + 0] = 0x7f;
  show[128 + 1] = 0x7f;
  j = 128 + 2;
  for (i = 0; i 《 30; i++)
  {
  show[j + i] = 0x60;
  }
  show[32 + 0] = 0xfe;
  show[32 + 1] = 0xfe;
  show[128 + 32 + 0] = 0x7f;
  show[128 + 32 + 1] = 0x7f;
  j = 32 + 2;
  for (i = 0; i 《 30; i++)
  {
  show[j + i] = 0x06;
  }
  show[64 + 0] = 0xfe;
  show[64 + 1] = 0xfe;
  show[128 + 64 + 0] = 0x7f;
  show[128 + 64 + 1] = 0x7f;
  j = 128 + 64 + 2;
  for (i = 0; i 《 30; i++)
  {
  show[j + i] = 0x60;
  }
  show[96 + 0] = 0xfe;
  show[96 + 1] = 0xfe;
  show[128 + 96 + 0] = 0x7f;
  show[128 + 96 + 1] = 0x7f;
  j = 96 + 2;
  for (i = 0; i 《 30; i++)
  {
  show[j + i] = 0x06;
  }
  }
  /**
  * OLED展示波形函数(仅波形)
  */
  void ShowSquareWave(void)
  {
  OLED_Picture_Part(show, 0, 128, 4, 2);
  }
  /**
  * 展示波形信息
  * @param pBuffer 时长数组指针
  * @param lenth 数组长度
  */
  void ShowDataAnalog(u16 * pBuffer, u16 lenth)
  {
  int page = 1;
  OLED_Fill_picture(0x00); //清屏
  OLED_ShowStr(0, 0, “Mode:show lenth”);
  OLED_ShowStr(0, 1, “Left:left page”);
  OLED_ShowStr(0, 2, “right:right page”);
  OLED_ShowStr(0, 3, “POWER:exit”);
  while (1)
  {
  key = Remote_Num();
  if (key == POWER)
  break;
  if (key == MODE)
  { //展示长度信息
  OLED_Fill_picture(0x00); //清屏
  OLED_ShowStr(0, 0, “Lenth: ”);
  OLED_ShowNum(6, 0, lenth, 4);
  }
  else if (key == LEFT || key == RIGHT || key == 1 || key == 9)
  {
  if (key == LEFT)
  {
  page -= 1;
  if (page 《= 1)
  page = 1;
  }
  else if (key == RIGHT)
  {
  page += 1;
  if (page 》= (lenth + 3) / 4)
  page = (lenth + 3) / 4;
  }
  else if (key == 1)
  {
  page = 1;
  }
  else if (key == 9)
  {
  page = (lenth + 3) / 4;
  }
  OLED_Fill_picture(0x00); //清屏
  OLED_ShowStr(0, 0, “P: Start: ”);
  OLED_ShowNum(2, 0, page, 2);
  OLED_ShowNum(11, 0, (page - 1) * 4 + 1, 4);
  ShowSquareWave();
  OLED_ShowNum(0, 3, pBuffer[(page - 1) * 4 + 0 + 1], 4);
  OLED_ShowNum(4, 1, pBuffer[(page - 1) * 4 + 1 + 1], 4);
  OLED_ShowNum(8, 3, pBuffer[(page - 1) * 4 + 2 + 1], 4);
  OLED_ShowNum(12, 1, pBuffer[(page - 1) * 4 + 3 + 1], 4);
  }
  }
  }
  /**
  * 展示输入信号信息函数
  */
  void ShowData(void)
  {
  while (1)
  {
  OLED_Fill_picture(0x00); //清屏
  OLED_ShowStr(0, 0, “Select From:”);
  OLED_ShowStr(0, 1, “1.input”);
  OLED_ShowStr(0, 2, “2.flash”);
  OLED_ShowStr(0, 3, “POWER:exit”);
  key = Remote_Num();
  if (key == POWER)
  break;
  if (key == 1)
  {//输入信息展示
  while (1)
  {
  OLED_Fill_picture(0x00); //清屏
  OLED_ShowStr(0, 0, “Select Mode:”);
  OLED_ShowStr(0, 1, “1.Digital”);
  OLED_ShowStr(0, 2, “2.Analog”);
  OLED_ShowStr(0, 3, “POWER:exit”);
  key = Remote_Num();
  if (key == POWER)
  break;
  else if (key == 1)
  {// 数字模式
  while (1)
  {
  OLED_Fill_picture(0x00); //清屏
  OLED_ShowStr(0, 0, “Getting.。.”);
  key = Remote_GetData();
  showData(key);
  key = Remote_Num(); //POWER退出,其它按键继续
  if (key == POWER)
  break;
  }
  }
  else if (key == 2)
  {// 模拟模式
  OLED_Fill_picture(0x00); //清屏
  OLED_ShowStr(0, 0, “Input after 2s!”);
  delay_ms(1000);
  OLED_ShowStr(0, 0, “Input after 1s!”);
  delay_ms(1000);
  OLED_Clean(0);
  Re_Record_ON();
  OLED_ShowStr(5, 0, “Input!”);
  delay_ms(1500);
  OLED_ShowStr(5, 1, “OK!”);
  ShowDataAnalog(Re_Record_Get(), Re_Record_OFF());
  }
  }
  }
  else if (key == 2)
  {//存储信息展示
  OLED_Fill_picture(0x00); //清屏
  OLED_ShowStr(0, 0, “Select key!”);
  while (1)
  {
  key = Remote_Num();
  if (key == POWER)
  break;
  else
  {
  int sta;
  data_Init();
  sta = GetData(addr + key, data);
  if (sta != -1)
  {
  if (((sta 》》 12) & 0x7) == 1) //模拟模式
  ShowDataAnalog(data, sta & 0x03FF);
  else if (((sta 》》 12) & 0x7) == 0) //标准模式
  {
  key = (data[1] 《《 16) + data[0];
  showData(key);
  }
  }
  else //未读取到数据
  {
  OLED_Fill_picture(0x00); //清屏
  OLED_ShowStr(0, 0, “Don’t have data!”);
  delay_ms(300);
  }
  }
  }
  }
  }
  }
  红外接收器驱动(remote)
  只展示了头文件(可以被外部调用的函数),使用前要调用Remote_Init() 进行初始化,Remote_Num() 用于正常的设备控制。
  Re_Record_ON();Re_Record_OFF(); 用于控制记录模式的开启和关闭,记录模式就是记录接收到的信号高低电平持续的时间,并存储在数组中,将数组的指针通过接口Re_Record_Get 传递出来,用于模拟发射或者存储。
  Remote_GetData 函数可以获取NEC红外数据的32位解码数据。
  头文件:
  #ifndef __RED_H
  #define __RED_H
  #include “sys.h”
  #define RDATA PBin(9) //红外数据输入脚
  #define USD 10
  #define RPT 11
  #define ADD 12
  #define LESS 13
  #define PLAY 14
  #define RIGHT 15
  #define VOLX 16
  #define LEFT 17
  #define MODE 18
  #define EQ 19
  #define POWER 20
  //单片机遥控器识别码为0
  #define REMOTE_ID 0
  extern u8 RmtCnt; //按键按下的次数
  /**
  * 打开红外接收
  */
  void Remote_ON(void);
  /**
  * 关闭红外接收
  */
  void Remote_OFF(void);
  /**
  * 红外传感器接收头引脚初始化
  */
  void Remote_Init(void);
  /**
  * 遥控扫描
  *
  * @return 0,没有任何按键按下;其他:按下的按键键值
  */
  u8 Remote_Scan(void);
  /**
  * 反馈数字(直到按键按下)
  *
  * @return 按下的按键值
  */
  u8 Remote_Num(void);
  /***************
  0: ERROR
  162: POWER 20
  98: MODE 18
  2: LEFT 17
  226: VOLX 16
  194: RIGHT 15
  34: PLAY 14
  224: EQ 19
  168: VOL- 13
  144: VOL+ 12
  104: 0 0
  152: RPT 11
  176: USD 10
  48: 1 1
  24: 2 2
  122: 3 3
  16: 4 4
  56: 5 5
  90: 6 6
  66: 7 7
  74: 8 8
  82: 9 9
  ***************/
  /**
  * 获得遥控器数据值
  * @return 数据值
  */
  u16 Remote_Get(void);
  /**
  * 开启记录模式
  * @return 记录数组的长度
  */
  void Re_Record_ON(void);
  /**
  * 关闭记录模式
  */
  u16 Re_Record_OFF(void);
  /**
  * 获取记录数组数据
  * @return 数据内容
  */
  u16* Re_Record_Get(void);
  /**
  * 确定首个数据是高低电平
  */
  u8 Re_Get_Type(void);
  /**
  * 得到32位红外数据信息
  *
  * @return 接受到的32位数据
  */
  u32 Remote_GetData(void);
  #endif
  外数据存储(remote_save)
  该驱动是对基础flash驱动的进一步抽象,主要是将红外数据的存储固定了格式,每一个红外数据占用351个16位空间,若初始地址已经固定,则每一个红外数据只要直到它的编号,就可以计算出存储地址,存储地址的第一个数据是概要信息(如下表),可以得到数据的类型、长度等信息,然后按需读取其后的数据存储空间,这样可以做到将NEC数据和模拟数据统一存储。
  [tr]地址用途[/tr]0[0-9]数据大小(1-350)
  0[10-11]保留
  0[12-14]数据类型(目前已知:0-》NEC; 1-》模拟编码存储; …)
  0[15]0-》未存储数据; 1-》存储了数据
  1-351数据存储空间
  PS:一个地址表示16位空间!!
  头文件:
  #ifndef __REMOTE_SAVE_H__
  #define __REMOTE_SAVE_H__
  #include “stmflash.h”
  //该驱动是再stmflash驱动的基础上进行了抽象,目的是为了方便红外数据的存储
  #define FLASH_SAVE_ADDR 0X08010000 //设置FLASH 保存地址(必须为偶数,且其值要大于本代码所占用FLASH的大小+0X08000000)RCT6最大3FFFF
  #define DATA_NUMBER 180 //设置最大的空间数
  #define MAX_LENTH (350 + 1) //设置一个空间占用flash大小(单位:16位)
  //16位状态字表示的信息:
  //
  //[15]:是否存储了数据
  //[14:12]:数据类型(目前已知:0-》NEC; 1-》模拟编码存储; 。..。.)
  //[9:0]:数据大小(1-350)
  //后接700个半字(u16)
  //读取地址:addr + N * (350 + 1)
  /**
  * 初始化所有区域保存标志位(首次使用请执行)
  * flash里面未使用空间默认为1,这会导致程序判断错误,所以执行这个函数可以初始化标志位(状态字[15])
  */
  void Save_Init(void);
  /**
  * 检测某一空间是否存储了数据
  * @param i 空间编码
  * @return 0:未保存; 1:已保存
  */
  int isSave(int i);
  /**
  * 删除某个空间保存标志位(即删除记录)
  * @param i 空间编码
  */
  void DelData(int i);
  /**
  * 删除某个区号所有区域保存标志位(即删除记录)
  * @param addr 区域首地址
  */
  void DelPartData(int addr);
  /**
  * 写入红外数据
  * @param i 空间编码
  * @param type 数据类型(目前已知:0-》NEC; 1-》模拟编码存储; 。..。.)
  * @param pBuffer 数据指针
  * @param lenth 半字(16位)数
  * @return 写入结果
  */
  int SaveData(int i, u8 type, u16 * pBuffer, u16 lenth);
  /**
  * 得到红外数据
  * @param i 空间编码
  * @param pBuffer 数据指针
  * @return 16位状态字
  * -1:地址错误或者未存储数据
  */
  int GetData(int i, u16 * pBuffer);
  #endif
  红外发射器驱动(irsend)
  红外发射驱动提供了两个接口,TR_SendData(u32 data) 用于发送标准NEC格式的32位数据,数据可以随意指定。
  TR_SendTimeData(u16 * pBuffer, u16 sta) 是统一数据发射接口,将从flash里面读取到的数据直接传入接口,与红外数据存储(remote_save)协议相同:
  sta 是int GetData(int i, u16 * pBuffer) 的返回值;
  pBuffer 则是int GetData(int i, u16 * pBuffer) 传入的数组指针。
  头文件:
  #ifndef __IRSEND_H__
  #define __IRSEND_H__
  #include “sys.h”
  #include “delay.h”
  #include “pwm.h” //依赖载波
  //红外端口定义
  //DAT -》 PA0
  #define IR_SEND PCout(2) // 红外发送控制
  /**
  * 红外发射模块初始化函数
  */
  void IR_SendPort_Init(void);
  /**
  * 发送标准的32位NEC数据
  *
  * @param data 32位要发送的数据
  */
  void TR_SendData(u32 data);
  /**
  * 统一数据发射接口(标志,模拟数据均可发送)
  *
  * @param pBuffer 要发送的数据数组指针(数据格式见remote_save.c和remote_save.h)
  * @param sta 数据的基本信息(数据格式见remote_save.c和remote_save.h)
  */
  void TR_SendTimeData(u16 * pBuffer, u16 sta);
  #endif
  载波:
  //pwm.h
  /*******************************************************************
  使用定时器TIM2的通道CH1输出38KHz的波形
  *******************************************************************/
  #ifndef __PWM_H__
  #define __PWM_H__
  #include “sys.h”
  /**
  * 定时器2PWM波形输出初始化
  */
  void TIM2_PWM_Init(u16 arr,u16 psc);
  #endif
  //pwm.c
  /*******************************************************************
  使用定时器TIM2的通道CH1输出38KHz的波形
  *******************************************************************/
  #include “pwm.h”
  #include “delay.h”
  /********************************************************************
  * Function Name : TIM2_PWM_Init(u16 arr,u16 psc)
  * Function : TIM2的通道CH1的PWM模式初始化
  * parameter : arr - 自动重装值
  psc - 时钟预分频数
  * Description : 频率f = 72M/[(psc+1)*(arr+1)]
  * Return : void
  *********************************************************************/
  //TIM2_PWM_Init(1895,0); 72000/(1895+1) = 37.99K
  /**
  * 定时器2PWM波形输出初始化
  */
  void TIM2_PWM_Init(u16 arr,u16 psc)
  {
  /* 初始化结构体定义 */
  GPIO_InitTypeDef GPIO_InitStructure;
  TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
  TIM_OCInitTypeDef TIM_OCInitStructure;
  /* 使能相应端口的时钟 */
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //使能定时器2时钟
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能GPIO外设时钟
  /* GPIOA.0初始化 */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; // TIM2 CH1
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // PA.0 复用推挽输出
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
  GPIO_SetBits(GPIOA,GPIO_Pin_0);
  /* TIM2 初始化*/
  TIM_TimeBaseInitStructure.TIM_Period = arr; //下一个更新事件装入活动的自动重装载寄存器周期的值
  TIM_TimeBaseInitStructure.TIM_Prescaler = psc; //作为TIMx时钟频率除数的预分频值
  TIM_TimeBaseInitStructure.TIM_ClockDivision = 0; //时钟分割:TDTS = Tck_tim
  TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
  TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
  /* 定时器TIM2 Ch1 PWM模式初始化 */
  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择定时器模式:TIM PWM1
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
  //TIM_OCInitStructure.TIM_Pulse = (arr+1)/2; //占空比 50%
  TIM_OCInitStructure.TIM_Pulse = (arr+1)/3; //占空比1:3
  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
  TIM_OC1Init(TIM2, &TIM_OCInitStructure);
  /* 使能TIM2在CCR1上的预装载寄存器 */
  TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Enable);
  /* 使能定时器 */
  TIM_Cmd(TIM2, ENABLE);
  }
举报

更多回帖

发帖
×
20
完善资料,
赚取积分