精华内容
下载资源
问答
  • 定时器中断输出脉冲

    2013-05-12 12:16:47
    本程序利用定时器中断输出脉冲led显示,led闪烁。
  • 电子-mini读中断脉冲定时器串口输出.rar,单片机/嵌入式STM32-F0/F1/F2
  • [第3讲]如何实现高速脉冲输出中断-中断flv,[第3讲]如何实现高速脉冲输出中断-中断。查看更多
  • 4种工作类型:内部方向控制的单相计数、外部方向控制的单相计数、双脉冲输入的加减计数、两路脉冲输入的双相正交计数;加速器程序仅用到第一种 根据有无外部硬件复位和启动输入,每种工作类型可设定3种工作状态:...

    1.中断

    1.1 中断源34个

    1.2 中断控制指令

    1.3 定时中断周期

    定时中断0,把周期时间值写入SMB34;定时中断1,把周期时间值写入SMB35;

    2.高速计数器

    2.1 高速计数器介绍

    • CPU224、CPU226拥有6个高速计数器HSC0-HSC5;
    • 4种工作类型:内部方向控制的单相计数、外部方向控制的单相计数、双脉冲输入的加减计数、两路脉冲输入的双相正交计数;加速器程序仅用到第一种
    • 根据有无外部硬件复位和启动输入,每种工作类型可设定3种工作状态:无复位、无启动输入,有复位、无启动输入,既有复位、又有启动输入;

     

     

     

     

    2.2 高速计数器指令

    2.3 高速计数器举例

     

    3 高速脉冲输出

    3.1 PWM简介

    • CPU数字量输出点Q0.0或Q0.1输出高速脉冲串PTO和脉宽调制波PWM;

     

     

     

    3.2 PWM举例

    我自己理解程序从脉宽100ms执行到150ms,只执行了一次,挡M0.0复位后,就固定在了150ms脉宽不再变化。

     

     

     

    展开全文
  • 在rk3288 android7.1上用RTC HYM8563实现定时功能,需要把HYM8563的中断输出脉冲形式,默认是,到了时间后一直是低电平。INT已经接了上拉电阻。 求大神指教。
  • 脉冲输出PORTA.0 方向信号输出PORTB.5 模仿PLC定位指令 可以作为简易运动控制器控制伺服电机 发脉冲两种目的 1)速度控制 2)位置控制 速度控制目的和模拟量一样,没有什么需要关注的地方 发送脉冲方式为PWM,速率...
  • STM32定时器单脉冲输出

    万次阅读 2016-04-26 16:50:34
    使用stm32cubemx配置外设,代码使用HAL stm32f1 v1.3.1库。...上图的意思是,TI2收到1给正脉冲,触发TIM1开始计数,经过 tDelay后,OC1输出低,经过一个tPulse后,OC1又恢复为高。 The OPM waveform

    使用stm32cubemx配置外设,代码使用HAL stm32f1 v1.3.1库。

    用的是stm32l152c开发板,时钟频率32MHZ。





    这里,没有配置中断。



    上图的意思是,TI2收到1给正脉冲,触发TIM1开始计数,经过 tDelay后,OC1输出低,经过一个tPulse后,OC1又恢复为高。


    The OPM waveform is defined by writing the compare registers (taking into account the clock frequency and the counter prescaler).
    • The tDELAY is defined by the value written in the TIMx_CCR1 register.
    • The tPULSEis defined by the difference between the auto-reload value and the compare value (TIMx_ARR - TIMx_CCR + 1).

    Let’s say you want to build a waveform with a transition from ‘0 to ‘1 when a compare match occurs and a transition from ‘1 to ‘0 when the counter reaches the auto-reload value. 

    To do this you enable PWM mode 2 by writing OC1M=111 in the TIMx_CCMR1 register. You can optionally enable the preload registers by writing OC1PE=1 in the 
    TIMx_CCMR1 register and ARPE in the TIMx_CR1 register. In thiscase you have to write the compare value in the TIMx_CCR1 register, the auto-reload value in the 
    TIMx_ARR register, generate an update by setting the UG bit and wait for external trigger event on TI2. CC1P is written to ‘0 in this example.

    向比较寄存器写入数值(考虑时钟频率和计数分频来计算)来定义OPM波形。

    1)tDelay值是TIMx_CCR1寄存器值

    2)tPulse的值是 自动重装值减掉比较值: (TIMx_ARR - TIMx_CCR + 1)


    假如,当比较相符发生时,你希望得到从0到1的波形,而当计数器达到自动重装值时,波形又从1变到0.

    这种情况,使用PWM模式2,TIMx_CCMR1 寄存器的OC1M要为111。可选:使能重装寄存器。 在此例子中,你需要把比较值写到TIMx_CCR1 寄存器,自动重装值写到TIMx_ARR寄存器,设置UG位产生一个更新事件,并且等待TI2的外部触发事件。CC1P被写为 0.


    看了手册上面的描述,就明白了:

    我按下按钮,延时2秒,点亮绿灯,停1秒,绿灯灭。


    如果是控制可控硅,就是:

    检测到零点,延时x微秒,触发可控硅,停1毫秒,关掉可控硅。 生成触发脉冲。

    可以让硬件自己处理,不用中断。


    开发板实现描述1.


      while (1)
      {
      /* USER CODE END WHILE */
    
      /* USER CODE BEGIN 3 */
    
        if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_SET) {
          HAL_Delay(100);
          
          if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_SET) {
            __HAL_TIM_ENABLE(&htim4);
            HAL_TIM_OnePulse_Start(&htim4, TIM_CHANNEL_2);
          }
        }
        
      }
      /* USER CODE END 3 */
    
    }

    HAL_TIM_OnePulse_Start函数有问题,它总是使能1、2两个通道,而且它不启用定时器的计数。

    因此,在它之前要使用宏 __HAL_TIM_ENABLE,置位 TIMx_CR1的CEN。


    需要注意到,单脉冲功能,只能在1、2通道上做。

    展开全文
  •   imx6 提供了一个 GPT 和两个 EPIT,共三个定时器中断,但是 GPT 已经被用作为系统的时钟中断,所以本文使用 EPIT 来实现 PWM 脉冲个数的输出,先确定 PWM 的周期,然后根据周期计算出对应脉冲所占用的时间,当...

    摘要:

      imx6 提供了一个 GPT 和两个 EPIT,共三个定时器中断,但是 GPT 已经被用作为系统的时钟中断,所以本文使用 EPIT 来实现 PWM 脉冲个数的输出,先确定 PWM 的周期,然后根据周期计算出对应脉冲所占用的时间,当时间达到设定时,产生定时中断,关闭 PWM 的输出。PWM 输出有多种方式,本文直接调用内核空间 PWM 中的API进行操作,将 PWM 中的部分参数放在设备树中。

    编写EPIT驱动存在的问题

    	GPC中断号 《设备树中》
    	a. 手册中对应的硬件中断号 - 32 =  interrupts = <0 56 IRQ_TYPE_LEVEL_HIGH>;
    	b. cat /proc/interrupts 第一个数为映射出的中断号   倒数第二个为硬件 GIC中断号 = 设备数
    	c. cd  /proc/device-tree 根节点下的所有属性和子节点
    	d. 定义全局指针时,一定要分配空间
    	e. 内核变量改变,应用空间调用时, ==》》 需上锁
    	f. 卸载驱动时,出现错误原因:定义一个reg 结构体指针时,如果需要进行地址ioremap映射,不应在kmalloc分配空间。
    

    EPIT 驱动设置步骤

    1. 先添加设备树文件,最好添加在最后调用的设备树文件
      需指定父中断:interrupt-parent = <&gpc> 或者直接放入 imx6qdl.dtsi 中;
      epit1: epit@020d0000 { /* EPIT1 */
                    compatible = "fsl,imx6q-epit1"; 
                    reg = <0x020d0000 0x4000>;
                    interrupts = <0 56 IRQ_TYPE_LEVEL_HIGH>;
      };
    
    
      epit2: epit@020d4000 { /* EPIT2 */
                    compatible = "fsl,imx6q-epit2"; 
                    reg = <0x020d4000 0x4000>;
                    interrupts = <0 57 IRQ_TYPE_LEVEL_HIGH>;
      };
    
    1. 在 include/dt-bindings/clock/imx6qdl-clock.h 添加两个宏
    	  #define IMX6QDL_CLK_EPIT1                        ***
     	  #define IMX6QDL_CLK_EPIT2                        ***
     	  //数字大小,定义在原来宏后面,防止 CLK[] 数组越界, 宏大小 < IMX6QDL_CLK_END;
    
    1. 添加时钟,【/sys/kernel/debug/clk/】开发板可用时钟目录
      在driver/clk/imx/clk-imx6q.c
        -> 在imx6q_clocks_init函数中添加:
      clk[IMX6QDL_CLK_EPIT1]        = imx_clk_gate2("epit1(/sys/kernel/debug/clk/名字)",        "ipg_per(/sys/kernel/debug/clk/名字/clk-rate)",    base + 0x6c(epit1 控制地址), 12 (epit1 clocks (epit1_clk_enable));
      clk[IMX6QDL_CLK_EPIT2]        = imx_clk_gate2("epit2",        "ipg_per",            base + 0x6c, 14);clk_register_clkdev(clk[IMX6QDL_CLK_EPIT1], "per(匹配的字符)", "imx-epit.1(匹配的字符)");
      clk_register_clkdev(clk[IMX6QDL_CLK_EPIT2], "per", "imx-epit.2");
      这里一定不能漏了,否则在驱动中clk_get_sys会失败的。clk_get_sys("imx-epit.2", "per");
    


    最后,给出一些与时钟有关的API函数:

    struct clk *__clk_lookup(const char *name) 通过时钟名找到时钟
    static inline int clk_enable(struct clk *clk) 使能时钟,不会睡眠
    static inline void clk_disable(struct clk *clk) 禁止时钟,不会睡眠
    static inline int clk_prepare_enable(struct clk *clk) 使能时钟,可能会睡眠
    static inline void clk_disable_unprepare(struct clk *clk) 禁止时钟,可能会睡眠
    static inline unsigned long clk_get_rate(struct clk *clk) 获取时钟频率
    static inline int clk_set_rate(struct clk *clk, unsigned long rate) 设置时钟频率
    static inline long clk_round_rate(struct clk *clk, unsigned long rate) 获取最接近的时钟频率
    static inline int clk_set_parent(struct clk *clk, struct clk *parent) 设置时钟的父时钟
    static inline struct clk *clk_get_parent(struct clk *clk) 获取时钟的父时钟
    

    驱动源文件

    #include "pwm_epit.h"
    
    pwm_dev *pwmdev;
    epit_reg *reg;
    
    
    /* Clear interrupt flag */
    static void clearinter(epit_reg *reg)
    {
    	writel(0x1, &(reg->EPITSR));
    }
    
    /* After request_irq enable epit by epit EPITCR register */
    static void epit_enable(epit_reg *reg, int isOn)
    {
    	u32 val;
    
    	val = readl(&(reg->EPITCR));
    	if(isOn) {
    		val |= EPITCR_EN;
    	} else {
    		val &= ~(EPITCR_EN);
    	}
    	
    	writel(val, &(reg->EPITCR));
    }
    
    /* Definite interrupt hander function */
    static irqreturn_t epit2_irq(int irq, void *dev_id)
    {
    	int val;
    	epit_reg *dev = (epit_reg *)dev_id;
    	
    	val = readl(&(dev->EPITSR));
    	if(val & (1 <<0))	{	/* judge compare event */
    		pwm_imx6_disable(pwmdev);
    		atomic_set(&pwmdev->flag, 1);
    		if (pwmdev->async_queue)
    			kill_fasync(&pwmdev->async_queue, SIGUSR1, POLL_IN);
    	}
    
    	clearinter(dev);
    	epit_enable(dev, 0);  /* exe only one */
    	return IRQ_HANDLED;
    }
    
    /* Init epit2 register */
    static int init_epit(pwm_dev *pwmdev)
    {
    	u32 val;
    	struct clk *timer_clk;
    	char name[15];
    	unsigned long rate;
    	unsigned int ret = 0;
    	
    	pwmdev->nd = of_find_node_by_path("/soc/aips-bus@02000000/epit@020d4000");
    //	countsdev.nd = of_find_compatible_node(NULL, NULL, "fsl,imx6q-epit2");
    	if(pwmdev->nd) {
    		reg = of_iomap(pwmdev->nd, 0);
    		pwmdev->irq = irq_of_parse_and_map(pwmdev->nd, 0);
    //		printk("irq = %d\r\n", countsdev.irq);
    //		printk("&reg.EPITCR = %x\r\n", &reg->EPITCR);
    //		printk("&reg.EPITSR = %x\r\n", &reg->EPITSR);
    //		printk("&reg.EPITLR = %x\r\n", &reg->EPITLR);
    //		printk("&reg.EPITCMPR = %x\r\n", &reg->EPITCMPR);
    //		printk("&reg.EPITCNR = %x\r\n", &reg->EPITCNR);
    	} else {
    			printk("can not find countsdev.nd!!!\n");
    			return -1;
    	}
    	
    	/* enable epit2 clock with per */
    	timer_clk = clk_get_sys("imx-epit.2", "per");
         	if (IS_ERR(timer_clk)) {
         	        printk("Faild to get timer_clk !\r\n");
                        return -1;
                }
    	 rate = clk_get_rate(timer_clk);
    	 printk(KERN_INFO"rate = %u\n", rate);
         clk_prepare_enable(timer_clk);
    	 
    	/* clearing register EPITCR */
    	writel(0, &(reg->EPITCR));
    
    	/* Init register EPITCR */				
         val = EPITCR_CLKSRC_PERIPHERAL|EPITCR_IOVW|EPITCR_WAITEN|EPITCR_STOPEN;
         val |= (EPITCR_RLD | EPITCR_OCIEN | EPITCR_ENMOD);
         writel(val, &(reg->EPITCR));
    	 printk("EPITCR = %x\r\n", readl(&(reg->EPITCR)));
    	 
    	 /* set value of load */		 
    //     writel(0, &(reg->EPITLR));
    		
    	/* set value register EPITCMPR, it will generate interrupt when the EPITCNR = EPITCMPR */  
         writel(0, &(reg->EPITCMPR));
    
    
    	/* request irq */
         memset(pwmdev->name, 0, sizeof(name));
         sprintf(pwmdev->name, "epit2_timer");
         ret = request_irq(pwmdev->irq, epit2_irq, IRQF_TRIGGER_NONE, pwmdev->name, reg);
         	if(ret < 0) {
    			return -EFAULT;
    	}
    
    	 return 0;
    }
    
    
    /* Set frac and timer timeout */
    /* Tout(s) = ((frac +1 )* value) / Tclk   */
    static void epit_set_count(epit_reg *reg, unsigned int frac, unsigned int value)
    {
    	u32 val;
    
    	if(frac > 0xFFF)  
    		frac = 0xFFF;
    	val = readl(&(reg->EPITCR));
    	val |= EPITCR_PRESC(frac);
    	writel(val, &(reg->EPITCR));
    
    	 /* set value of load */	
    	writel(value, &(reg->EPITLR)); 
    }
    
    
    /******************************************************************************/
    /*
     *  unify API with PWM in kernel
     *  set/get/enable/disbale PWM parament by ususal API interface 
     */
     
    /* update pwm paraments */
    static void pwm_imx6_update(pwm_dev *pwmdev)
    {
        pwm_config(pwmdev->pwm, pwmdev->pwminfo.duty_ns, pwmdev->pwminfo.period_ns);
    }
    
    /* enable pwm */
    static void pwm_imx6_enable(pwm_dev *pwmdev)
    {
        pwm_enable(pwmdev->pwm);
    }
    
    /* disable pwm */
    static void pwm_imx6_disable(pwm_dev *pwmdev)
    {
        //set duty_ns = 0 before shutdowm pwm
        pwmdev->pwminfo.duty_ns= 0;
        pwm_imx6_update(pwmdev);
        pwm_disable(pwmdev->pwm);
    }
    
    /* set pwm period_ns */
    static void pwm_imx6_set_period(pwm_dev *pwmdev, unsigned int period_ns)
    {
        pwmdev->pwminfo.period_ns = period_ns;
        pwm_set_period(pwmdev->pwm, pwmdev->pwminfo.period_ns);
    }
    
    /* get pwm period_ns */
    static unsigned int pwm_imx6_get_period(pwm_dev *pwmdev)
    {
        return pwm_get_period(pwmdev->pwm);
    }
    
    
    /******************************************************************************/
    /* init filp_operation functions */
    static int pwm_imx6_open(struct inode *inode, struct file *filp)
    {
        filp->private_data = pwmdev;   
        return 0;
    }
    
    static ssize_t pwm_imx6_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
    {
    	int ret = 0;
    	unsigned char tem_flag = 0;
    	pwm_dev *dev = (pwm_dev *)filp->private_data;
    
    	tem_flag = atomic_read(&dev->flag);
    	atomic_set(&dev->flag, 0);
    	ret = copy_to_user(buf, &tem_flag, sizeof(tem_flag));
    	if (ret < 0) {
    		printk("kernel read failed!!!\r\n");
    		return -EINVAL;
    	}
    	
    	return 0;
    }
    
    static int pwm_imx6_fasync(int fd, struct file *filp, int on)
    {
    	int ret;
    	
    	pwm_dev *dev = (pwm_dev *)filp->private_data;
    	ret = fasync_helper(fd, filp, on, &dev->async_queue);
    	if (ret < 0)
    		return -EIO;
    	return 0;
    }
    
    static long pwm_imx6_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
    {
        unsigned int ret;
        filp->private_data = pwmdev;
        
        switch (cmd)
        {
            case PWM_B_SET_PARA:
    			 // tripple args to be checked
    			 ret = copy_from_user(&paraConfigs, (struct pwm_para_config __user *)arg,
    					    					 sizeof(struct pwm_para_config));
    			 if (ret) {
    					printk("copy user failed\n");
    					return -EFAULT;
    			 }
    			 
              		             pwmdev->pwminfo.polarity = paraConfigs.c_polarity;
    			 pwmdev->pwminfo.period_ns = paraConfigs.c_period_ns;
    			 pwmdev->pwminfo.duty_ns  = paraConfigs.c_duty_ns;
    			 pwmdev->ms_counts = (unsigned long)paraConfigs.c_counts;
    			 
    			 if(pwmdev->ms_counts < 30000) { /* prevent overflow interrupt */
    				 pwmdev->ms_counts *= 66000;	
    				 pwmdev->ms_counts -= 66*200; /* compensation 200 us */
    				 epit_set_count(reg, 0,  pwmdev->ms_counts); /* set paraConfigs.c_counts(ms) interrupt */
    			} else if (pwmdev->ms_counts < 100000) {
    				 pwmdev->ms_counts /= 1000;
    				 pwmdev->ms_counts *= 100000;	
    				 pwmdev->ms_counts -= 2000; /* compensation 200 us */
    				 epit_set_count(reg, 659,  pwmdev->ms_counts); /* set paraConfigs.c_counts(ms) interrupt */
    			 } else {
    			 	 pwmdev->ms_counts /= 100000;
    				 pwmdev->ms_counts *= 2000000;	
    				 pwmdev->ms_counts -= 4; /* compensation 200 us */
    				 epit_set_count(reg, 3299,  pwmdev->ms_counts); /* set paraConfigs.c_counts(ms) interrupt */
    			 }
    				 
    			 pwm_set_polarity(pwmdev->pwm, pwmdev->pwminfo.polarity);
    			 pwm_imx6_update(pwmdev);
    			 pwm_imx6_enable(pwmdev);	 			           
    			 epit_enable(reg, 1);
                 break;
                
            case PWM_B_GET_PARA:
    			 paraConfigs.c_polarity = pwmdev->pwminfo.polarity;
    			 paraConfigs.c_period_ns = pwmdev->pwminfo.period_ns;
    			 paraConfigs.c_duty_ns = pwmdev->pwminfo.duty_ns;
    			 
                 ret = copy_to_user((struct pwm_para_config __user *)arg, &paraConfigs, 
    					    					 sizeof(struct pwm_para_config));
            
                 if (ret) {
                     	printk("copy_to_user failed.");
                     	return -EFAULT;
                 }
                 break;
                
            case PWM_B_ENABLE:
                 pwm_imx6_enable(pwmdev);
                 break;
                
            case PWM_B_DISABLE:
                pwm_imx6_disable(pwmdev);
                break;
                
            default:
                printk("pwmdev: cmd error!\n");
                return -EFAULT;
        }
        
        return 0;
    }
    
    
    static int pwm_imx6_release(struct inode *inode, struct file *filp)
    {
        filp->private_data = pwmdev;
        atomic_inc(&pwmdev->flag);  
    //  pwm_imx6_disable(pwmdev);   pwm disable when call close function in use spcae
        
        return pwm_imx6_fasync(-1, filp, 0);;
    }
    
    struct file_operations pwm_imx6_fops = {
        .owner = THIS_MODULE,
        .open = pwm_imx6_open,
        .release = pwm_imx6_release,
        .unlocked_ioctl = pwm_imx6_ioctl,
        .fasync = pwm_imx6_fasync,
        .read = pwm_imx6_read,
    };
    
    
    /*********	 get pwm-b informations from device tree   *********/
    static ssize_t pwm_imx6_parse_dt(struct platform_device *pdev)
    {
    	struct device_node *node = pdev->dev.of_node;
        int ret;
    
        if (!node) {
            dev_err(&pdev->dev, "pwm-b: Device Tree node missing\n");
            return -EINVAL;
        }
        
        ret = of_property_read_u32(node, "pwmchannel", &pwmdev->pwminfo.channel);
        if (ret < 0) {
            dev_err(&pdev->dev, "pwm-b: pwmchannel missing\n");
            return ret;
        }
    
        ret = of_property_read_u32(node, "period_ns", &pwmdev->pwminfo.period_ns);
        if (ret < 0) {
            dev_err(&pdev->dev, "pwm-b: period_ns missing\n");
            return ret;
        }
        
        ret = of_property_read_u32(node, "duty_ns", &pwmdev->pwminfo.duty_ns);
        if (ret < 0) {
            dev_err(&pdev->dev, "pwm-b: duty_ns missing\n");
            return ret;
        }
    
        return 0;
    }
    
    
    
    /********************  probe function  **************************/
    static int pwm_probe(struct platform_device *pdev)
    {
    	int ret;
    	pwmdev = kzalloc(sizeof(pwm_dev), GFP_KERNEL);
    	if (!pwmdev) {
    		return -ENOMEM;
    	}
    	
    	/* creater device number */
    	if (pwmdev->major) {   /* definite device number */
    		pwmdev->devid = MKDEV(pwmdev->major, 0);
    		register_chrdev_region(pwmdev->devid, PWM_DEVICE, 
    			PWM_DEV_NAME);
    		} else {			/* without definite device number */
    		alloc_chrdev_region(&pwmdev->devid, 0, PWM_DEVICE,  
    			PWM_DEV_NAME);
    		pwmdev->major = MAJOR(pwmdev->devid);	 /* get major device number */
    		pwmdev->minor = MINOR(pwmdev->devid);   /* get minor device number */
    		}
    
    		printk(KERN_INFO"pwmdev major=%d,minor=%d\r\n", pwmdev->major,
    		pwmdev->minor);
    
    
    	/* Init cdev  */
    	pwmdev->cdev.owner = THIS_MODULE;
    	cdev_init(&pwmdev->cdev, &pwm_imx6_fops);
    
    	/* add a cdev */
    	ret = cdev_add(&pwmdev->cdev, pwmdev->devid, PWM_DEVICE);
    	if(ret < 0) {
    		printk(KERN_INFO"error : cdev_add\r\n");
    		return ret;
    	}
    
    	/* creater a class */
    	pwmdev->class = class_create(THIS_MODULE, PWM_DEV_NAME);
    	if(IS_ERR(pwmdev->class)) {
    		ret = PTR_ERR(pwmdev->class);
    		goto error_class_create;
    	}
    
    	/* creater /device/PWM_DEV_NAME */
    	pwmdev->device = device_create(pwmdev->class, NULL, pwmdev->devid, NULL, PWM_DEV_NAME);
    	if(IS_ERR(pwmdev->device)) {
    		ret = PTR_ERR(pwmdev->device);
    		goto error_device_create;
    	}
    
    	/* default paraments pwm from device tree */
                ret = pwm_imx6_parse_dt(pdev);
       	if (ret < 0) {
            		dev_err(&pdev->dev, "pwm-b: Device not found\n");
            		return -ENODEV;
        	}	
     	
    	/* request pwm-b device */
       	pwmdev->pwm = pwm_request(pwmdev->pwminfo.channel, "pwm-b");
    
        	if (IS_ERR(pwmdev->pwm)) {
            		dev_err(&pdev->dev, "pwm-b: unable to request legacy PWM\n");
            		ret = PTR_ERR(pwmdev->pwm);
            		return ret;
        	}
    	
    	/* set default paraments */
    	pwm_imx6_update(pwmdev);
    
    	/* pwm_set_polarity before enable pwm, and after set pwm paraments */
        ret = pwm_set_polarity(pwmdev->pwm, PWM_POLARITY_NORMAL);
        if (ret < 0)
            	printk("pwm set polarity fail, ret = %d\n", ret);
    
    	init_epit(pwmdev);
    	
    	/* Init flag */
    	atomic_set(&pwmdev->flag, 0);
    
    	return 0;
    
    error_device_create:
    	class_destroy(pwmdev->class); 
    error_class_create:
    	cdev_del(&pwmdev->cdev);  
    	kfree(pwmdev);
    	return ret;	
    
    }
    
    
    static int pwm_remove(struct platform_device *dev)
    {
    	free_irq(pwmdev->irq, reg);
    	
    	/* release map address */
    	iounmap(reg);
    	
    	/* disable pwm_device */
    	pwm_imx6_disable(pwmdev);
    
    	/* free pwm_device */
    	pwm_free(pwmdev->pwm);
    	
    	/* logout char device */
    	device_destroy(pwmdev->class, pwmdev->devid);
    
    	class_destroy(pwmdev->class);
    
    	cdev_del(&pwmdev->cdev);
    
    	unregister_chrdev_region(pwmdev->devid, PWM_DEVICE);
    	
    	/* release point to pwmdev after pwmdev->devid */	
    	kfree(pwmdev);
    	
    	printk(KERN_INFO"unregister_chrdev ok !!!\r\n");
    	
    	return 0;
    }
    
    
    /********************  match table  **************************/
    static const struct of_device_id pwm_of_match[] = {
    	{ .compatible = "pwm-pulse" },
    	{ /* Sentinel */ }
    };
    
    MODULE_DEVICE_TABLE(of, pwm_of_match);
    
    static struct platform_driver pwm_driver = {
    	.driver = {
    			.name = "pwm",
    			.of_match_table = pwm_of_match,
    	},
    
    	.probe = pwm_probe,
    	.remove = pwm_remove,
    };
    
    
    static int __init pwm_driver_init(void)
    {
    	return platform_driver_register(&pwm_driver);
    }
    
    static void __exit pwm_driver_exit(void)
    {
    	platform_driver_unregister(&pwm_driver);
    }
    
    
    module_init(pwm_driver_init);
    module_exit(pwm_driver_exit);
    MODULE_LICENSE("GPL");
    MODULE_AUTHOR("zsj");
    MODULE_DESCRIPTION("pwm b send 1 ms pulse!!!");
    MODULE_ALIAS("pwm-b");
    
    展开全文
  • stm32同一定时器使用两个通道输出不同频率的pwm,想用中断方式对两路pwm的脉冲个数进行计数,但同一定时器只有一个中断函数怎么办?
  • STM32 F1x 固定PWM个数输出,...启用GPIO口输入中断,在中断中进行调频和计数 下面是各部分代码: 3. TIM3计数输出PWM void tim3_pwm_init(u16 arr,u16 psc) { //这部分为计数器PWM输出,可参考例程。不再多讲 ...

    STM32 F1x 固定PWM个数输出,同时调频。模拟曲线可以达到预期

    MDK模拟
    以上是在软件中模拟得到的波形。
    程序思路:

    1. 启用通用计数器TIM3 的通道二进行PWM输出
    2. 启用GPIO口输入中断,在中断中进行调频和计数

    下面是各部分代码:
    3. TIM3计数输出PWM

    void tim3_pwm_init(u16 arr,u16 psc)
    {
    	//这部分为计数器PWM输出,可参考例程。不再多讲
    	GPIO_InitTypeDef gpio_pwm_str;
    	TIM_TimeBaseInitTypeDef tim_pwm_base_init_str;
    	TIM_OCInitTypeDef tim_pwm_oc_init_str;
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    	
    	gpio_pwm_str.GPIO_Pin=GPIO_Pin_7;
    	gpio_pwm_str.GPIO_Mode=GPIO_Mode_AF_PP;
    	gpio_pwm_str.GPIO_Speed=GPIO_Speed_50MHz;
    	GPIO_Init(GPIOA,&gpio_pwm_str);
    	
    	tim_pwm_base_init_str.TIM_Period=arr;
    	tim_pwm_base_init_str.TIM_Prescaler=psc;
    	tim_pwm_base_init_str.TIM_ClockDivision=TIM_CKD_DIV1;
    	tim_pwm_base_init_str.TIM_CounterMode=TIM_CounterMode_Up;
    	TIM_TimeBaseInit(TIM3,&tim_pwm_base_init_str);
    	
    	tim_pwm_oc_init_str.TIM_OCMode=TIM_OCMode_PWM1;
    	tim_pwm_oc_init_str.TIM_OutputState=TIM_OutputState_Enable;
    	tim_pwm_oc_init_str.TIM_OCPolarity=TIM_OCPolarity_High;
    	tim_pwm_oc_init_str.TIM_Pulse=arr/2;
    	TIM_OC2Init(TIM3,&tim_pwm_oc_init_str);
    	
    	TIM_OC2PreloadConfig(TIM3,TIM_OCPreload_Enable);
    	
    	TIM_Cmd(TIM3,ENABLE);
    	
    }
    
    1. 初始化中断,和中断服务函数。在中断服务中进行调频 即改变ARR寄存器的值。同时采用全局变量进行计数
    void EXTIX_Init(void)
    {
    	EXTI_InitTypeDef exti_init_str;
    	NVIC_InitTypeDef exti_nvic_init_str;
    	
    	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource7);
    
    	//³õʼ»¯ÖжÏÏß	
    	exti_init_str.EXTI_Line=EXTI_Line7;
    	exti_init_str.EXTI_LineCmd=ENABLE;
    	
    	//ÖÐ¶Ï »òÕß Ê¼þ
    	exti_init_str.EXTI_Mode=EXTI_Mode_Interrupt;
    	
    	//´¥·¢·½Ê½
    	exti_init_str.EXTI_Trigger=EXTI_Trigger_Falling;
    	EXTI_Init(&exti_init_str);
    	
    	//³õʼ»¯ÖжÏ
    	exti_nvic_init_str.NVIC_IRQChannel=EXTI9_5_IRQn;
    	exti_nvic_init_str.NVIC_IRQChannelCmd=ENABLE;
    	exti_nvic_init_str.NVIC_IRQChannelPreemptionPriority=2;
    	exti_nvic_init_str.NVIC_IRQChannelSubPriority=2;
    	NVIC_Init(&exti_nvic_init_str);
    }
    
    void EXTI9_5_IRQHandler(void)
    {
    	plu_user--;	
    	TIM3->ARR = cnt_user; 
    	TIM3->CCR2 = cnt_user/2; 
    	TIM3->CNT = TIM3->CCR1;  //这句话必加
    	cnt_user-=20;
    	if(cnt_user<=71)
    	{
    		cnt_user=71;
    	}
    	if(plu_user<=1)
    	{
    		TIM_Cmd(TIM3,DISABLE);
    	}
    	//ÊÖ¶¯¸´Î»±ê־λ
    	EXTI_ClearITPendingBit(EXTI_Line7);
    }
    
    1. 主程序代码:不要忘记作为中断传值的全局变量
    int main(void)
    {
    	vu8 key;
    	plu_user=200;
    	cnt_user=719;
    	delay_init();	    	 //ÑÓʱº¯Êý³õʼ»¯	  
    	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //ÉèÖÃNVICÖжϷÖ×é2:2λÇÀÕ¼ÓÅÏȼ¶£¬2λÏìÓ¦ÓÅÏȼ¶
    	uart_init(115200);	 //´®¿Ú³õʼ»¯Îª115200
    	LED_Init();		  		//³õʼ»¯ÓëLEDÁ¬½ÓµÄÓ²¼þ½Ó¿Ú
    	KEY_Init();         	//³õʼ»¯Óë°´¼üÁ¬½ÓµÄÓ²¼þ½Ó¿Ú
    	EXTIX_Init();
    	
    	while(1)
    	{	
    		printf("OK\r\n");	
    		
    		key=KEY_Scan(0);
    		if(key)
    		{
    			switch(key)
    			{
    				case KEY0_PRES:
    					GPIO_ResetBits(GPIOA,GPIO_Pin_5);
    					delay_ms(5);
    					
    					tim3_pwm_init(719,49);
    					
    					break;
    				case KEY1_PRES:
    					GPIO_SetBits(GPIOA,GPIO_Pin_5);
    					delay_ms(5);
    					
    					tim3_pwm_init(719,49);
    					
    					break;
    			}
    		}
    	}
    }
    
    

    欢迎大家进行讨论,小白一枚,水平有限,希望大家见谅。

    展开全文
  • 脉冲调制(PWM)是利用微处理器对数字输出来对模拟电路的一种非常有效的技术。简单点说就是对确定频率的信号,调整其占空比。   stm32的定时器除了TIM6和TIM7外,其他定时器都可以产生PWM输出。其中高级定时器TIM1...
  • (hal库)定时器1输出多路脉冲宽度可变的PWM控制电机(中断方式) 分为以下步骤 /***************************************************************************/ 1、stm32cubeMX配置项目参数 2、使用sw4stm32软件...
  • 1、TIM1 输出pwm.频率为 1 K 。引脚用PA11。 2、TIM3 配置为外部时钟输入模式。引脚用PD2。使能中断。...3、将PD2 和 PA11 短接,主函数串口打印 pwm脉冲个数。 4、控制TIME1 pwm 输出 4个周期后 停止输出
  • //定义负脉冲输出端口 sbit mi=P3^2; //定义外部中断0输入口 void main() { TMOD=0x22; //T0和T1设置为定时方式2 EA=1; ET0=1; //开T0中断 EX0=1; //开外部中断0 PT0=1; //T0中断设为高...
  • STM32输出可控数量与频率的脉冲

    千次阅读 2019-08-30 17:35:12
    关于脉冲输出的控制我查阅网上资料后发现有五种方法 1、单脉冲法,需要一个脉冲中断一次,中断次数多,影响效率 2、一个定时器输出PWM,另一定时器进行中断计数,与方法1一样,同样需要频繁的中断 3、用主从...
  • IO口输出不同占空比的脉冲/***************************************************************************TH0=0xb1;TL0=0xdf;25hz(很闪)TH0=0xc9;TL0=0x4f;35hz(闪)TH0=0xd5;TL0=0x07;43hz(微闪)TH0=0xdd;TL0=0x9f;...
  • STM32F103输出固定数量脉冲用于控制步进电机

    千次阅读 多人点赞 2020-10-05 14:27:29
    参考了网上大神的指导,我的思路是:用两个定时器(一个用于PWM输出,一个用于中断PWM输出),通过对PWM的周期和输出时间的控制,来达到输出固定脉冲数的目的。 下面为主要代码: #include <sys.h> #...
  • 当要控制步进电机或其他...STM32中发出脉冲一般有两种方式:1)利用定时中断输出脉冲,但是间隔的延时会影响其他主程序的进程,当控制多个电机的时候就非常不可取;2)利用PWM脉宽调制,并通过主从定时器进行设定,...
  • 利用定时器/计数器T0产生定时,采用中断方式,让8个发光二极管每隔1s依次点亮,全亮后全灭,再次开始循环;数码管从1开始,每点亮一个发光二极管,显示+1,显示9时二极管全灭,再次开始循环;系统的晶振频率为12MHz...
  • STM32输出固定数量的PWM脉冲

    千次阅读 2020-08-22 17:17:59
    STM32输出固定数量的PWM脉冲 X_xxieRiemann关注 0.2122018.01.21 20:59:07字数 493阅读 8,743 主要程序参照CSDN上的文章《stm32主从模式定时器产生精确脉冲个数》进行修改,原文是以定时器4作为主模式输出PWM,...
  • 本文以STM32F405单片机为例,介绍如何用一个定时器的四个通道独立地输出四路PWM脉冲。主要使用定时器输出比较的翻转功能和捕获比较中断
  • STM32精确输出PWM脉冲数控制电机 发脉冲两种目的 1)速度控制 2)位置控制 速度控制目的和模拟量一样,没有什么需要关注的地方 发送脉冲方式为PWM,速率稳定而且资源占用少 stm32位置控制需要获得发送的脉冲数,有...
  • 在低压伺服上,因为需要在驱动器上对采集的增量式的编码器脉冲数等效输出,方便上层的控制器做闭环(某些场合需求) 所以需要在stm32上实现正交编码器等效输出输出两路相位相差90度,脉冲数任意的PWM 相位差使用...
  • STM32中发出脉冲一般有两种方式:1)利用定时中断输出脉冲,但是间隔的延时会影响其他主程序的进程,当控制多个电机的时候就非常不可取;2)利用PWM脉宽调制,并通过主从定时器进行设定,好处是不占用主程序时钟,且...
  • 一个对输出PWM脉冲计数(计时)。 1.门控方式能实现,但需要复杂的配置和计算,不推荐。 2.脉冲计数是比较实际,也是比较简单的方式; 对输出PWM脉冲计数(计时)方法有多种: 1.IO中断计数,或同步定时中断计数...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 464
精华内容 185
关键字:

中断脉冲输出