嵌入式Linux开发13——PWM输出实验

背景知识

  我们用PWM信号控制LCD的背光,PWM 信号有两个关键的术语:频率和占空比,频率就是开关速度,把一次开关算作一个周期,那么频率就是 1 秒内进行了多少次开关。占空比就是一个周期内高电平时间和低电平时间的比例,一个周期内高电平时间越长占空比就越大,反之占空比就越小。占空比用百分之表示,如果一个周期内全是低电平那么占空比就是 0%,如果一个周期内全是高电平那么占空比就是100%。
在这里插入图片描述
  我们给 LCD 的背光引脚输入一个 PWM 信号,这样就可以通过调整占空比的方式来调整LCD 背光亮度了。提高占空比就会提高背光亮度,降低占空比就会降低背光亮度。重点就在于PWM 信号的产生和占空比的控制,很幸运的是, I.MX6U 提供了 PWM 外设,因此我们可以配置 PWM 外设来产生 PWM 信号。
  可以通过配置相应的寄存器来设置 PWM 信号的频率和占空比, PWM 的 16 位计数器是个向上计数器,此计数器会从 0X0000 开始计数,直到计数值等于寄存器 PWMx_PWMPR(x=1~8)+ 1,然后计数器就会重新从 0X0000 开始计数,如此往复。所以寄存器 PWMx_PWMPR 可以设 PWM 的频率。在一个周期内, PWM 从 0X0000 开始计数的时候, PWM 引脚先输出高电平(默认情况下,可以通过配置输出低电平)。采样 FIFO 中保存的采样值会在每个时钟和计数器值进行比较,当采样值和计数器相等的话 PWM 引脚就会改为输出低电平(默认情况下,同样可以通过配置输出高电平)。计数器会持续计数,直到和周期寄存器 PWMx_PWMPR(x=1~8) + 1 的值相等,这样一个周期就完成了。所以,采样 FIFO 控制着占空比,而采样 FIFO 里面的值来源于采样寄存器PWMx_PWMSAR,因此相当于PWMx_PWMSAR 控制着占空比。至此, PWM 信号的频率和占空比设置我们就知道该如何去做了。
  接下来我们使用I.MX6ULL的PWM1,PWM1输出引脚为GPIO1_IO8,配置步骤为:
1、配置引脚 GPIO1_IO8
  配置 GPIO1_IO08 的复用功能,将其复用为 PWM1_OUT 信号线。
2、初始化 PWM1
  初始化 PWM1,配置所需的 PWM 信号的频率和默认占空比。
3、设置中断
  因为 FIFO 中的采样值每个周期都会少一个,所以需要不断的向 FIFO 中写入采样值,防止其为空。我们可以使能 FIFO 空中断,这样当 FIFO 为空的时候就会触发相应的中断,然后在中断处理函数中向 FIFO 写入采样值。
4、使能 PWM1
  配置好 PWM1 以后就可以开启了。

程序编写

  我们要在PWM.c中编写6个函数,首先是函数pwm1_irqhandler,这个是 PWM1 的中断处理函数。需要在此函数中处理 FIFO 空中断,当 FIFO 空中断发生以后需要向采样寄存器PWM1_PWMSAR 写入采样数据,也就是占空比值,最后要清除相应的中断标志位;第 2 个函数是 backlight_init,这个是背光初始化函数,在此函数里面会初始化背光引脚 GPIO1_IO08,将其复用为 PWM1_OUT。然后此函数初始化 PWM1,设置要产生的 PWM 信号频率和默认占空比,接下来使能 FIFO 空中断,注册相应的中断处理函数,最后使能 PWM1;第 3 个函数是pwm1_enable,用于使能 PWM1;第 4 个函数是pwm1_setsample_value,用于设置采样值,也就是寄存器 PWM1_PWMSAR 的值;第 5 个函数是 pwm1_setperiod_value,用于设置 PWM 信号的频率;第 6 个函数是 pwm1_setduty,用于设置 PWM 的占空比,函数内部会根据百分值计算出寄存器 PWM1_PWMSAR 应该设置的值。

/* 背光设备 */
struct backlight_dev_struc backlight_dev;

/*
 * @description	: pwm1中断处理函数
 * @param		: 无
 * @return 		: 无
 */
void pwm1_irqhandler(void)
{

	if(PWM1->PWMSR & (1 << 3)) 	/* FIFO为空中断 */
	{
		/* 将占空比信息写入到FIFO中,其实就是设置占空比 */
		pwm1_setduty(backlight_dev.pwm_duty); 
		PWM1->PWMSR |= (1 << 3); /* 写1清除中断标志位 */ 
	}
}

/*
 * @description	: 初始化背光PWM
 * @param		: 无
 * @return 		: 无
 */
void backlight_init(void)
{
	unsigned char i = 0;
	
	/* 1、背光PWM IO初始化 */
	IOMUXC_SetPinMux(IOMUXC_GPIO1_IO08_PWM1_OUT, 0); /* 复用为PWM1_OUT */

	/* 配置PWM IO属性	
	 *bit 16:0 HYS关闭
	 *bit [15:14]: 10 100K上拉
	 *bit [13]: 1 pull功能
	 *bit [12]: 1 pull/keeper使能
	 *bit [11]: 0 关闭开路输出
	 *bit [7:6]: 10 速度100Mhz
	 *bit [5:3]: 010 驱动能力为R0/2
	 *bit [0]: 0 低转换率
	 */
	IOMUXC_SetPinConfig(IOMUXC_GPIO1_IO08_PWM1_OUT, 0XB090);
	
	/* 2、初始化PWM1		*/
	/*
   	 * 初始化寄存器PWMCR
   	 * bit[27:26]	: 01  当FIFO中空余位置大于等于2的时候FIFO空标志值位
   	 * bit[25]		:
 0  停止模式下PWM不工作
   	 * bit[24]		: 0	  休眠模式下PWM不工作
   	 * bit[23]		: 0   等待模式下PWM不工作
   	 * bit[22]		: 0   调试模式下PWM不工作
   	 * bit[21]		: 0   关闭字节交换
   	 * bit[20]		: 0	  关闭半字数据交换
   	 * bit[19:18]	: 00  PWM输出引脚在计数器重新计数的时候输出高电平
   	 *					  在计数器计数值达到比较值以后输出低电平
   	 * bit[17:16]	: 01  PWM时钟源选择IPG CLK = 66MHz
   	 * bit[15:4]	: 65  分频系数为65+1=66,PWM时钟源 = 66MHZ/66=1MHz
   	 * bit[3]		: 0	  PWM不复位
   	 * bit[2:1]		: 00  FIFO中的sample数据每个只能使用一次。
   	 * bit[0]		: 0   先关闭PWM,后面再使能
	 */
	PWM1->PWMCR = 0;	/* 寄存器先清零 */
	PWM1->PWMCR |= (1 << 26) | (1 << 16) | (65 << 4);

	/* 设置PWM周期为1000,那么PWM频率就是1M/1000 = 1KHz。 */
	pwm1_setperiod_value(1000);

	/* 设置占空比,默认50%占空比   ,写四次是因为有4个FIFO */
	backlight_dev.pwm_duty = 50;
	for(i = 0; i < 4; i++)
	{
		pwm1_setduty(backlight_dev.pwm_duty);	
	}
	
	/* 使能FIFO空中断,设置寄存器PWMIR寄存器的bit0为1 */
	PWM1->PWMIR |= 1 << 0;
	system_register_irqhandler(PWM1_IRQn, (system_irq_handler_t)pwm1_irqhandler, NULL);	/* 注册中断服务函数 */
	GIC_EnableIRQ(PWM1_IRQn);	/* 使能GIC中对应的中断 */
	PWM1->PWMSR = 0;			/* PWM中断状态寄存器清零 */
	
	pwm1_enable();				/* 使能PWM1 */

	
}

/*
 * @description	: 使能PWM
 * @param		: 无
 * @return 		: 无
 */
void pwm1_enable(void)
{
	PWM1->PWMCR |= 1 << 0;	 
}

/*
 * @description		: 设置Sample寄存器,Sample数据会写入到FIFO中,
 * 					  所谓的Sample寄存器,就相当于比较寄存器,假如PWMCR中的POUTC
 *				  	  设置为00的时候。当PWM计数器中的计数值小于Sample的时候
 *					  就会输出高电平,当PWM计数器值大于Sample的时候输出底电平,
 *					  因此可以通过设置Sample寄存器来设置占空比
 * @param -  value	: 寄存器值,范围0~0XFFFF
 * @return 			: 无
 */
void pwm1_setsample_value(unsigned int value)
{
	PWM1->PWMSAR = (value & 0XFFFF);	
}

/*
 * @description		: 设置PWM周期,就是设置寄存器PWMPR,PWM周期公式如下
 *					  PWM_FRE = PWM_CLK / (PERIOD + 2), 比如当前PWM_CLK=1MHz
 *					  要产生1KHz的PWM,那么PERIOD = 1000000/1K - 2 = 	998
 * @param -  value	: 周期值,范围0~0XFFFF
 * @return 			: 无
 */
void pwm1_setperiod_value(unsigned int value)
{
	unsigned int regvalue = 0;

	if(value < 2)
		regvalue = 2;
	else 
		regvalue = value - 2;
	PWM1->PWMPR = (regvalue & 0XFFFF);
}

/*
 * @description		: 设置PWM占空比
 * @param -  value	: 占空比0~100,对应0%~100%
 * @return 			: 无
 */
void pwm1_setduty(unsigned char duty)
{
	unsigned short preiod;
	unsigned short sample;

	backlight_dev.pwm_duty = duty;
	preiod = PWM1->PWMPR + 2;
	sample = preiod * backlight_dev.pwm_duty / 100;
	pwm1_setsample_value(sample);
}


  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

贾贾乾杯

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值