当前位置: 首页 > news >正文

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;
}
http://www.xdnf.cn/news/1312309.html

相关文章:

  • 19.3 Transformers量化模型极速加载指南:4倍推理加速+75%显存节省实战
  • 头文件包含和前置声明
  • 什么是微前端?
  • 超越Transformer:大模型架构创新的深度探索
  • 数据结构:二叉平衡树
  • OpenCV 图像处理基础操作指南(二)
  • ClickHouse的学习与了解
  • 概率论基础教程第3章条件概率与独立性(三)
  • Linux sar命令详细使用指南
  • Qt 动态属性(Dynamic Property)详解
  • Qt 关于QString和std::string数据截断的问题- 遇到\0或者0x00如何处理?
  • 【经典上穿突破】副图/选股指标,双均线交叉原理,对价格波动反应灵敏,适合捕捉短期启动点
  • [1Prompt1Story] 注意力机制增强 IPCA | 去噪神经网络 UNet | U型架构分步去噪
  • PowerShell 第11章:过滤和比较(上)
  • 云安全 - The Big IAM Challenge
  • 二分查找。。
  • 智能合约:区块链时代的“数字契约革命”
  • AutoDL使用学习
  • 【Java web】Servlet 详解
  • CUDA 编程笔记:CUDA延迟隐藏
  • [优选算法专题二滑动窗口——最大连续1的个数 III]
  • huggingface TRL中是怎么获取参考模型的输出的
  • Swift 实战:实现一个简化版的 Twitter(LeetCode 355)
  • 新手向:GitCode疑难问题诊疗
  • Java 10 新特性及具体应用
  • 嵌入式硬件篇---电感串并联
  • 2^{-53} 单位舍入误差、机器精度、舍入的最大相对误差界限
  • 实例分割-动手学计算机视觉13
  • docker安装mongodb及java连接实战
  • Effective C++ 条款45:运用成员函数模板接受所有兼容类型