pwn定时器,ARM定时delay 外部中断用函数指针(统一)day55,56
九:PWN定时器
一:基础概念
PWM:脉宽调制
周期:一次高电平开始到下次高电平开始的时间
频率:1/T
占空比:高电平占整个周期的比例
S3C2440A有5个16位定时器。其中定时器0、1、2和3具有脉宽调制(PWM)功能。定时器4是一个无输出引脚的内部定时器。定时器0还包含用于大电流驱动的死区发生器。
S3C2440A有5个16位定时器。其中定时器0、1、2和3具有脉宽调制(PWM)功能。定时器4是一个无输出引脚的内部定时器。定时器0还包含用于大电流驱动的死区发生器。
定时计数缓冲寄存器(TCNTBn)包含了一个当使能了定时器时的被加载到递减计数器中的初始值。定时比较缓冲寄存器(TCMPBn)包含了一个被加载到比较寄存器中的与递减计数器相比较的初始值。这种TCNTBn和TCMPBn的双缓冲特征保证了改变频率和占空比时定时器产生稳定的输出
每个定时器有它自己的由定时器时钟驱动的16位递减计数器。当递减计数器到达零时,产生定时器中断请求通知CPU定时器操作已经完成。当定时器计数器到达零时,相应的TCNTBn的值将自动被加载到递减计数器以继续下一次操作。然而,如果定时器停止了,例如,在定时器运行模式期间清除TCONn的定时器使能位,TCNTBn的值将不会被重新加载到计数器中。
时钟频率越低,时间越慢
二:配置
定时器使用:
1.计数寄存器和比较寄存器初始化(前提私用PWN)
2.配置时钟
3.设置工作模式(单次/自动重载)
4.如果使用PWM(设置极性)
5.使能中断(如果需要)
6.启动定时器
三:代码
#include <s3c2440.h>
#include "pwm.h"void pwm_init(void)
{/* 1. 配置 GPB0 为 TOUT0 */GPBCON &= ~(0x3 << 0);GPBCON |= (0x2 << 0);/* 2. 配置 Timer0 */TCFG0 |= (24 << 0); // Timer0预分频TCFG1 &= ~(0xF << 0); // MUX0=1/2分频TCNTB0 = 1000; // 1kHz PWMTCMPB0 = 500; // 50%占空比/* 3. 启动 Timer0 */TCON &= ~(1 << 4); //关闭死区TCON |= (1 << 3); // 自动重载TCON |= (1 << 2); //极性变换 TCON |= (1 << 1); //更新CNT,CMP TCON |= (1 << 0); //启动定时器TCON &= ~(1 << 1); // 清除手动更新
}
四:定时器延时delay
#include <s3c2440.h>
#include "delay.h"unsigned char flag;void delay_1ms(void)
{unsigned char cnt = 0;flag = 0;INTMSK &= ~(1 << 14);TCNTB4 = 1000;TCFG0 &= ~(0xff << 8);TCFG0 |= (24 << 8);TCFG1 &= ~(0xf << 16);TCON |= (1 << 22);TCON &= ~(1 << 22);TCON |= (1 << 21);TCON &= ~(1 << 21);TCON |= (1 << 20);while(!flag) //第二次进入才清零{cnt = TCNTO4;}
}void delay_ms(unsigned int n)
{while(n--){delay_1ms();}
}
十:ADC
一:读启动,每次读之后自动启动
但是如果第二次读隔了一段时间,读到只是上次启动时候的值
void adc_init(void)
{// ADC时钟50M / (49 + 1) // 通道默认为0 // 使能读启动ADCCON = (1 << 14) | (49 << 6) | (1 << 1);
}void adc_set_channel(unsigned char channel)
{ADCCON &= ~(0x7 << 3);ADCCON |= ((channel & 0x7) << 3);
}unsigned short adc_read()
{unsigned char t = 5;unsigned short data = ADCDAT0;while((!(ADCCON & (1 << 15))) && t--){delay_ms(1);}data = ADCDAT0 & 0x3ff;return data;
}
二:手动启动转换
可以自己控制何时启动,然后在读,然后读到的值就是及时更新的启动值
void adc_init(void)
{// ADC时钟50M / (49 + 1) // 通道默认为0 ADCCON = (1 << 14) | (49 << 6);
// INTSUBMSK &= ~(1 << 10);
// INTMSK &= ~(1 << 31);
}void adc_set_channel(unsigned char channel)
{ADCCON &= ~(0x7 << 3);ADCCON |= ((channel & 0x7) << 3);
}void adc_start(void) //手动启动,自己控制时间
{ADCCON |= (1 << 0);
}unsigned short adc_read()
{unsigned char t = 5;unsigned short data = 0; // ADCDAT0;while((!(ADCCON & (1 << 15))) && t--){delay_ms(1);}data = ADCDAT0 & 0x3ff;return data;
}
十一:外部中断预设函数,函数指针
//irq.h
#ifndef __IRQ_H
#define __IRQ_Htypedef void (*irq_handler_t)();//定义函数指针类型typedef enum __irq_num_t
{IRQ_EINT0, IRQ_EINT1, IRQ_EINT2, IRQ_EINT3, IRQ_EINT4_7, IRQ_EINT8_23,IRQ_CAM, IRQ_nBATT_FLT,IRQ_TICK, IRQ_WDT_AC97,IRQ_TIMER0, IRQ_TIMER1, IRQ_TIMER2, IRQ_TIMER3, IRQ_TIMER4, IRQ_UART2, IRQ_LCD, IRQ_DMA0, IRQ_DMA1, IRQ_DMA2,IRQ_DMA3, IRQ_SDI, IRQ_SPI0, IRQ_UART1, IRQ_NFCON, IRQ_USBD, IRQ_USBH, IRQ_IIC, IRQ_UART0, IRQ_SPI1,IRQ_RTC, IRQ_ADC, IRQ_EINT4,IRQ_EINT5, IRQ_EINT6, IRQ_EINT7, IRQ_EINT8, IRQ_EINT9,IRQ_EINT10, IRQ_EINT11, IRQ_EINT12, IRQ_EINT13, IRQ_EINT14,IRQ_EINT15, IRQ_EINT16, IRQ_EINT17, IRQ_EINT18, IRQ_EINT19,IRQ_EINT20, IRQ_EINT21, IRQ_EINT22, IRQ_EINT23,IRQ_SUB_NUM,IRQ_UART0_RXD,IRQ_UART0_TXD,IRQ_UART0_ERR,IRQ_INT_AC97,IRQ_MAX
}irq_num_t; //对应中断值typedef enum __eint_trigger_t //对应的标志,00,01,10,11,000等
{TRIG_LOW,TRIG_HIGHT,TRIG_FALLING,TRIG_RASING = 4,TRIG_DOUBLE = 6,TRIG_NONE
}eint_trigger_t;void request_irq(irq_num_t irq, irq_handler_t handler, eint_trigger_t trig);#endif
#include <s3c2440.h>
#include "irq.h"static irq_handler_t irq_handler[60];void deal_eint4_7(void)//单独处理的header函数,会放进函数指针数组中
{unsigned char i = 0;for(i = IRQ_EINT4; i <= IRQ_EINT7; i++){ if(EINTPEND & (1 << (i - IRQ_EINT4 + 4))){irq_handler[i]();EINTPEND |= (1 << (i - IRQ_EINT4 + 4));break;}}
}void deal_eint8_23(void)
{unsigned char i = 0;for(i = IRQ_EINT8; i <= IRQ_EINT23; i++){ if(EINTPEND & (1 << (i - IRQ_EINT8 + 8))){irq_handler[i]();EINTPEND |= (1 << (i - IRQ_EINT8 + 8));break;}}
}void deal_uart0(void)
{if(SUBSRCPND & (1 << 0)) //IRQ_UART0_RXD - IRQ_SUB_NUM - 1 {irq_handler[IRQ_UART0_RXD]();SUBSRCPND |= (1 << 0);}else if(SUBSRCPND & (1 << 1)){irq_handler[IRQ_UART0_TXD]();SUBSRCPND |= (1 << 1);}else{irq_handler[IRQ_UART0_ERR]();SUBSRCPND |= (1 << 2);}
}void irq_init(void)//初始化
{unsigned char i = 0;for(i = 0; i < IRQ_MAX; i++)//IRQ_MAX,用的枚举,从0开始,所以对应函数会通过匹配来放进对应指针函数数组的下标{if((IRQ_EINT4_7 == i)){irq_handler[i] = deal_eint4_7; //把写好的函数放入指针数组中} else if((IRQ_EINT8_23 == i)){irq_handler[i] = deal_eint8_23; }else if(IRQ_UART0 == i){irq_handler[i] = deal_uart0;}}
//MSK,,默认11-屏蔽 0-开启INTMSK &= ~(1 << IRQ_EINT4_7);//直接全部使能,就不用再判断要不要使能了,以后都要改,每个都要判断INTMSK &= ~(1 << IRQ_EINT8_23);INTMSK &= ~(1 << IRQ_ADC);INTMSK &= ~(1 << IRQ_UART0);
}void request_irq(irq_num_t irq, irq_handler_t handler, eint_trigger_t trig)
{irq_handler[irq] = handler; //对应函数放进对应指针数组中//开始匹配if(irq <= IRQ_EINT3){GPFCON &= ~(0x3 << ((irq - IRQ_EINT0) * 2));//中断对应引脚GPFCON |= (0x2 << ((irq - IRQ_EINT0) * 2));EXTINT0 &= ~(0x7 << ((irq - IRQ_EINT0) * 4));//对应外部中断控制寄存器EXTINT0 |= (trig << ((irq - IRQ_EINT0) * 4));}else if(irq <= IRQ_EINT7 && irq >= IRQ_EINT4){GPFCON &= ~(0x3 << ((irq - IRQ_EINT4 + 4) * 2));GPFCON |= (0x2 << ((irq - IRQ_EINT4 + 4) * 2));EXTINT0 &= ~(0x7 << ((irq - IRQ_EINT4 + 4) * 4));EXTINT0 |= (trig << ((irq - IRQ_EINT4 + 4) * 4));}else if(irq <= IRQ_EINT15 && irq >= IRQ_EINT8){GPGCON &= ~(0x3 << ((irq - IRQ_EINT8) * 2));GPGCON |= (0x2 << ((irq - IRQ_EINT8) * 2));EXTINT1 &= ~(0x7 << ((irq - IRQ_EINT8) * 4));EXTINT1 |= (trig << ((irq - IRQ_EINT8) * 4));}else if(irq <= IRQ_EINT23 && irq >= IRQ_EINT16){GPFCON &= ~(0x3 << ((irq - IRQ_EINT16 + 8) * 2));GPFCON |= (0x2 << ((irq - IRQ_EINT16 + 8) * 2));EXTINT2 &= ~(0x7 << ((irq - IRQ_EINT16) * 4));EXTINT2 |= (trig << ((irq - IRQ_EINT16) * 4));}if(irq <= IRQ_ADC){INTMSK &= ~(1 << irq);}else if(irq <= IRQ_EINT23 && irq >= IRQ_EINT4){EINTMASK &= ~(1 << (irq - IRQ_EINT4 + 4));}else if(irq <= IRQ_INT_AC97 && irq >= IRQ_UART0_ERR){// 使能SRCINTSUBMSK &= (1 << (irq - IRQ_SUB_NUM - 1)); }
}void c_deal_irq(void)
{// 1. 判断哪个中断源触发中断 并 处理// 清中断标志unsigned int irq_num = INTOFFSET;irq_handler[irq_num]();SRCPND |= (1 << irq_num);INTPND = INTPND;
}