嵌入式开发记录-day28 ioremap+PWM 驱动蜂鸣器

1、常见两种蜂鸣器

  蜂鸣器发出声音是因为震动,震动需要频率,就是说需要晶振;震动的频率高低,发出高低的声音;
  有源蜂鸣器:有源蜂鸣器通电就可以响,里面自带了晶振,就可以发出声音;

  无源蜂鸣器:需要外部给一定频率的脉冲信号,占空比也可以调节;高低电平切换,控制震动与不震动;

2、查看原理图

  GPD0_0--->MOTOR_PWM --->beep

  pwm + ioremap() 控制
3、需要用的寄存器地址:

  1、PWM的地址0x139D0000

  GPD0CON地址0x11400000

4、pwm.c

#include <linux/init.h>
#include <linux/module.h>

#include <linux/kernel.h>
#include <linux/fs.h>
#include <mach/gpio.h>
#include <plat/gpio-cfg.h>
#include <linux/miscdevice.h>
#include <linux/platform_device.h>
//#include <mach/gpio-bank.h>
#include <mach/regs-gpio.h>
#include <asm/io.h>
#include <linux/regulator/consumer.h>
//#include "gps.h"
#include <linux/delay.h>

MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("TOPEET");

// PWM定时器相关的寄存器
struct {
    unsigned int    TCFG0;  
    unsigned int    TCFG1;  
    unsigned int    TCON;  
    unsigned int    TCNTB0;  
    unsigned int    TCMPB0;  
    unsigned int    TCNTO0;  
    unsigned int    TCNTB1;  
    unsigned int    TCMPB1;  
    unsigned int    TCNTO1;  
    unsigned int    TCNTB2;  
    unsigned int    TCMPB2;  
    unsigned int    TCNTO2;  
    unsigned int    TCNTB3;  
    unsigned int    TCMPB3;  
    unsigned int    TCNTO3;  
    unsigned int    TCNTB4;  
    unsigned int    TCNTO4;  
    unsigned int    TINT_CSTAT;    // 每个都是4字节
}*PWM;

// 定义物理地址 虚拟地址
volatile unsigned long phys_addr,phys_GPD0_addr,virtl_addr,virtl_GPD0_addr;
// 定义寄存器地址变量
volatile unsigned long *GPD0CON,*GPD0PUD;
  
void addr_Init(void)
{
    phys_addr = (unsigned long)0x139D0000;   // PWM 基地址
    virtl_addr = (unsigned long)ioremap(phys_addr,0x32);  // 虚拟地址
    PWM = (unsigned long*)(virtl_addr + 0x0);    
    /*
    GPD0CON 
    Base Address: 0x1140_0000
  Address = Base Address + 0x00A0

    GPD0PUD
  Base Address: 0x1140_0000
  Address = Base Address + 0x00A8 
    */
    phys_GPD0_addr = 0x11400000 + 0xA0;  // 端口基地址
    virtl_GPD0_addr = (unsigned long)ioremap(phys_GPD0_addr, 0x10);
    GPD0CON = (unsigned long*)(virtl_GPD0_addr + 0x00);     // 控制寄存器地址
    GPD0PUD = (unsigned long*)(virtl_GPD0_addr + 0x00A8-0x00A0); // 上下电位寄存器地址
}  
void beepOn(void)
{
    //开启自动重载 0x1 = Starts Timer 0 
    // 1 = Interval mode (auto-reload)   开启自动自动加载 翻转 | 0x1 | 0x8;    
    (*PWM).TCON = (((*PWM).TCON) & (~(0xf))) | 0x9;
}  
// 
void beepOff(void)
{
    // 关闭定时器0
    (*PWM).TCON = ((*PWM).TCON & (~(0xf)) )| 0x0;
    //定时器结束之后,输出的是高电平还是低电平?
    // GPD0_0设置为输入
    *GPD0CON =  (*GPD0CON&(~(0xf)))|0x0;
}  
  
void pwmdev_Init(void)
{
    addr_Init();
    // 配置GPD0_0为定时器输出 0x2 = TOUT_0
    *GPD0CON = (*GPD0CON & (~(0xf)) )| 0x2;
    // 上下拉输出 0x0 = Disables Pull-up/Pull-down
    *GPD0PUD = *GPD0PUD & (~(0xf));  //失能上下拉
    
    // 设置预分频 0x1111 1001    249
    (*PWM).TCFG0 = ((*PWM).TCFG0 &(~(0xff)))|0xf9;
    //分频1.2.4.8.16
    (*PWM).TCFG1 = ((*PWM).TCFG1 &(~(0xf)))|0x2;
    //设置占空比
    (*PWM).TCMPB0 = 50;
    (*PWM).TCNTB0 = 100;
    //设置手动加载,开启定时器   | 0x1 | 0x2;    
    (*PWM).TCON = ((*PWM).TCON & (~(0xf)) )| 0x3;
    
}

int pwm_init(void)
{
    pwmdev_Init();
    beepOn();
    return 0;
}

void pwm_exit(void)
{
    beepOff();
}

module_init(pwm_init);
module_exit(pwm_exit);

5、编译后加载模块蜂鸣器响,卸载后蜂鸣器关闭

 

posted @ 2020-08-08 18:33  笑不出花的旦旦  阅读(332)  评论(0)    收藏  举报