-
MAX32625/MAX32630学习:10位ADC采样(解析及注意事项),中断式和非中断式
2018-03-19 13:15:10给大家分享一下MAX32630的ADC采样程序,包括中断式和非中断式。首先,我们来比较一下STM32F4与MAX32630在ADC方面的区别:STM32F4:(1)12位ADC(2)支持DMA(3)每个ADC通道自带数据寄存器(4)最大转换速率2.4...给大家分享一下MAX32630的ADC采样程序,包括中断式和非中断式。
首先,我们来比较一下STM32F4与MAX32630在ADC方面的区别:
STM32F4:
(1)12位ADC
(2)支持DMA
(3)每个ADC通道自带数据寄存器
(4)最大转换速率2.4MHz
MAX32630:
(1)10位ADC
(2)不支持DMA
(3)每个ADC通道共用一个数据寄存器
(4)最大转换速率8MHz
下面给出非中断式和中断式的ADC采样程序
[mw_shl_code=c,true]/***** Includes *****/
#include <stdio.h>
#include <stdint.h>
#include "mxc_config.h"
#include "led.h"
#include "adc.h"
#include "nhd12832.h"
#include "board.h"
#include "max14690.h"
#include "tmr_utils.h"
/***** Definitions *****/
const max14690_cfg_t max14690_cfg2 = {
.ldo2mv = 3300, /**< 3.3v in mV, connected to VDDB */
.ldo2mode = MAX14690_LDO_MPC1, /**< Enalbe LDO2 when +5v is present on VBUS */
.ldo3mv = 3300, /**< 3.3v is L3OUT -- optional */
.ldo3mode = MAX14690_LDO_ENABLED /**< Enable the LDO. */
};
#define CLOCK 23
/*------------------------------------------------------------
usÑóê±oˉêy
------------------------------------------------------------*/
void delay_us(uint32_t us)
{
uint32_t n;
while(us--)for(n=0;n<CLOCK;n++);
}
/*------------------------------------------------------------
msÑóê±oˉêy
------------------------------------------------------------*/
void delay_ms(uint32_t ms)
{
while(ms--)delay_us(1000);
}
/* Change to #undef USE_INTERRUPTS for polling mode */
#define USE_INTERRUPTS 1
//#undef USE_INTERRUPTS 注释掉为中断式,不注释则为非中断式
/***** Globals *****/
#ifdef USE_INTERRUPTS
volatile unsigned int adc_done = 0;
#endif
/***** Functions *****/
#ifdef USE_INTERRUPTS
void AFE_IRQHandler(void)
{
ADC_ClearFlags(MXC_F_ADC_INTR_ADC_DONE_IF);
/* Signal bottom half that data is ready */
adc_done = 1;
return;
}
#endif
/* ************************************************************************* */
void ADC0_StartConvert(mxc_adc_chsel_t channel, unsigned int adc_scale, unsigned int bypass)
{
uint32_t ctrl_tmp;
/* Clear the ADC done flag */
ADC_ClearFlags(MXC_F_ADC_INTR_ADC_DONE_IF);
MXC_ADC->intr |= MXC_F_ADC_INTR_ADC_DONE_IE;
/* Insert channel selection */
ctrl_tmp = MXC_ADC->ctrl;
ctrl_tmp &= ~(MXC_F_ADC_CTRL_ADC_CHSEL);
ctrl_tmp |= ((channel << MXC_F_ADC_CTRL_ADC_CHSEL_POS) & MXC_F_ADC_CTRL_ADC_CHSEL);
/* Clear channel configuration */
ctrl_tmp &= ~(MXC_F_ADC_CTRL_ADC_REFSCL | MXC_F_ADC_CTRL_ADC_SCALE | MXC_F_ADC_CTRL_BUF_BYPASS);
/* ADC reference scaling must be set for all channels but two*/
if ((channel != ADC_CH_VDD18) && (channel != ADC_CH_VDD12)) {
ctrl_tmp |= MXC_F_ADC_CTRL_ADC_REFSCL;
}
/* Finalize user-requested channel configuration */
if (adc_scale || channel > ADC_CH_3) {
ctrl_tmp |= MXC_F_ADC_CTRL_ADC_SCALE;
}
if (bypass) {
ctrl_tmp |= MXC_F_ADC_CTRL_BUF_BYPASS;
}
/* Write this configuration */
MXC_ADC->ctrl = ctrl_tmp;
/* Start conversion */
MXC_ADC->ctrl |= MXC_F_ADC_CTRL_CPU_ADC_START;
}
int main(void)
{
uint16_t adc_val[4];
unsigned int overflow[4];
uint8_t fmtstr[40];
/* Initialize ADC */
ADC_Init();
MAX14690_Init(&max14690_cfg2);
#ifdef USE_INTERRUPTS
NVIC_EnableIRQ(AFE_IRQn);
#endif
while(1) {
/* Convert channel 0 */
#ifdef USE_INTERRUPTS
adc_done = 0;
ADC0_StartConvert(ADC_CH_0, 0, 1);
while (!adc_done);
#else
ADC_StartConvert(ADC_CH_0, 0, 1);
#endif
overflow[0] = (ADC_GetData(&adc_val[0]) == E_OVERFLOW ? 1 : 0);
/* Delay for 1/4 second before next reading */
TMR_Delay(MXC_TMR0, MSEC(250));
}
}
[/mw_shl_code]
用KEIL开发的小伙伴们需要注意的几个问题是:
(1)//#undef USE_INTERRUPTS 注释掉为中断式,不注释则为非中断式
(2)ADC的参考电压为内部参考电压1.2V
(3)ADC源代码中断式采样会出现死循环,原因在于ADC_ClearFlags(MXC_F_ADC_INTR_ADC_DONE_IF);这条语句把ADC中断使能也清零了,如图所示,adc_done_ie清零,无法进入中断,程序会一直while (!adc_done);死循环。在源代码的void ADC0_StartConvert(这是我自己定义的函数,源代码中的为void ADC_StartConvert)中,在ADC_ClearFlags(MXC_F_ADC_INTR_ADC_DONE_IF);后加一条语句MXC_ADC->intr |= MXC_F_ADC_INTR_ADC_DONE_IE;,重新使能ADC中断,编译后测试成功
下次我给大家分享一下如何配置ADC通道的电压测量范围,主要有四种测量范围:(1)0~0.6V;(2)0~1.2V;(3)0~3V;(4)0~6V(AIN0和AIN1最大容忍电压为5V)。 -
java可中断式获取锁与超时等待获取锁
2018-11-30 11:08:05java的Lock体系相比synchronize具有一些更方便的特性,比如锁...一、可中断式获取锁 可响应中断式锁调用的方法是lock.lockInterruptibly() public void lockInterruptibly() throws InterruptedException { ...java的Lock体系相比synchronize具有一些更方便的特性,比如锁可以响应中断以及超时等待等特性,我们可以通过看源码来看看响应中断是如何实现的。
一、可中断式获取锁
可响应中断式锁调用的方法是lock.lockInterruptibly()
public void lockInterruptibly() throws InterruptedException { sync.acquireInterruptibly(1); }
而lockInterruptibly()会调用AQS的acquireInterruptibly()模板方法
public final void acquireInterruptibly(int arg) throws InterruptedException { //增加了对中断状态的判断, //如果检测线程中断状态改变,抛出中断异常后方法直接退出 if (Thread.interrupted()) throw new InterruptedException(); if (!tryAcquire(arg)) //线程获取锁失败 doAcquireInterruptibly(arg); }
在获取同步状态失败后就会调用doAcquireInterruptibly方法:
private void doAcquireInterruptibly(int arg) throws InterruptedException { // 将节点插入到同步队列中 final Node node = addWaiter(Node.EXCLUSIVE); boolean failed = true; try { for (;;) { final Node p = node.predecessor(); //获取锁出队 if (p == head && tryAcquire(arg)) { setHead(node); p.next = null; // help GC failed = false; return; } if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) //线程被阻塞时,若检测到中断则抛出中断异常后退出 throw new InterruptedException(); } } finally { if (failed) cancelAcquire(node); } }
这段代码以中断模式独占获取同步状态,与acquire方法逻辑几乎一致,唯一的区别是当parkAndCheckInterrupt返回true时即线程阻塞时该线程被中断,代码抛出被中断异常。
二、超时等待获取锁
超时等待获取锁就是在中断获取锁的基础上增加超时功能
调用lock.tryLock(timeout,TimeUnit)方法实现超时等待获取锁的效果,该方法会在三种情况下才会返回:
- 在超时时间内,当前线程成功获取了锁;
- 当前线程在超时时间内被中断;
- 超时时间结束,仍未获得锁返回false
tryLock(timeout,TimeUnit)源码
public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException { return sync.tryAcquireNanos(1, unit.toNanos(timeout)); }
该方法本质调用AQS的模板方法public final boolean tryAcquireNanos(int arg, long nanosTimeout)
public final boolean tryAcquireNanos(int arg, long nanosTimeout) throws InterruptedException { if (Thread.interrupted()) throw new InterruptedException(); return tryAcquire(arg) || doAcquireNanos(arg, nanosTimeout); }
最终调用doAcquireNanos()方法实现超时等待效果
private boolean doAcquireNanos(int arg, long nanosTimeout) throws InterruptedException { // 传入时间小于0 方法直接退出,线程获取锁失败 if (nanosTimeout <= 0L) return false; // 根据超时时间和当前时间计算出截止时间 final long deadline = System.nanoTime() + nanosTimeout; final Node node = addWaiter(Node.EXCLUSIVE); boolean failed = true; try { for (;;) { final Node p = node.predecessor(); // 当前线程获得锁出队列 if (p == head && tryAcquire(arg)) { setHead(node); p.next = null; // help GC failed = false; return true; } // 再次计算截止时间-当前时间值(重新计算超时时间) nanosTimeout = deadline - System.nanoTime(); // 已超时,线程直接退出 if (nanosTimeout <= 0L) return false; // if (shouldParkAfterFailedAcquire(p, node) && nanosTimeout > spinForTimeoutThreshold) // 在超时时间内仍未被唤醒,线程退出 LockSupport.parkNanos(this, nanosTimeout); //线程被中断抛出被中断异常 if (Thread.interrupted()) throw new InterruptedException(); } } finally { if (failed) cancelAcquire(node); } }
逻辑图如下
-
中断式按键驱动定时器防抖
2019-09-22 23:23:54修改中断服务程序,在中断服务程序中加入定时器,利用定时器产生软中断:在定时器timer_function中处理按键中断响 应。原理:抖动不重复进入中断服务处理函数,即不重复进入timer_function。 ...为何要防抖:看如下按键波形
由于按键的机械振动,按键一次可能产生多次上升沿或下降沿,触发多次中断,而重复几次进入中断服务程序,上报重复键值,产生抖动。
如何通过软件消去按键抖动
修改中断服务程序,在中断服务程序中加入定时器,利用定时器产生软中断:在定时器timer_function中处理按键中断响 应。原理:抖动不重复进入中断服务处理函数,即不重复进入timer_function。
上升下降沿的 抖动时间间隔在10ms以内,在此时间内产生抖动,重新给定时器赋值,使其不触发timer_function, 这得益于函数int mod_timer(struct timer_list *timer, unsigned long expires),改变定时器的值,重新计时:触发中断后,调用 mod_timer给定时器赋值10ms,如果在第5ms产生抖动,又一次触发中断,进入中断函数,再次调用 mod_timer给定时器重新赋值。则15m后进入timer_function。以此类推。按键中断服务程序处理(timer_function)是后一次抖动进入中断服函数的10ms之后。防止抖动。
代码实现:
先讲解timer_list 的结构体:
struct timer_list { struct list_head entry, unsigned long expires,//定时器到期的时间,当expires小于等于jiffies时,这个定时器便到期并调用定时器超时处理函数,然后就不会 再调用了,比如要使用10ms后到期,赋值(jiffies+HZ/100)即可 void (*function)(unsigned long ),//定时器超时处理函数。 unsigned long data,//传递到*function超时处理函数的参数,可以通过参数来获取信息 struct timer_base_s *base, }
function:定义了定时器超时处理函数,从使用的角度来将是最关键的。
expires:定义了相对目前的延时时间。当前时间用jiffiers来度量,延时一秒用expires=jiffiers+Hz,延时10秒就是expires=jiffiers+10*Hz,延时10ms就是expires=jiffiers+Hz/100。如果没有对其初始化,或者初始化为0,则激活定时器之后,内核会拿expires和jiffiers比较,当expires<jiffiers是,定时器就已经超时,则超时处理函数不会执行。
data:传递给超时处理函数function的参数。如果函数function不需要传递参数,则data可以不用配置。
另外两个参数不需要我们配置,由内核帮我们完成。
entry:添加到内核链表
base:指定处理器,由init_timer完成。
两个全局变量:
jiffies: 是系统时钟,全局变量,默认每隔10ms加1
HZ:是每S的频率,通过系统时钟换算出来,比如每隔10ms加1,那么HZ就等于100**
定时器常用函数
init_timer(struct timer_list*) //定时器初始化结构体函数, add_timer(struct timer_list*) //往系统添加定时器,告诉内核有个定时器结构体 mod_timer(struct timer_list *, unsigned long jiffier_timerout) //修改定时器的超时时间为jiffies_timerout, 当expires小于等于jiffies时,便调用定时器超时处理函数。 timer_pending(struct timer_list *) //定时器状态查询,如果在系统的定时器列表中则返回1,否则返回0; del_timer(struct timer_list*) //删除定时器,在本驱动程序出口函数sixth_drv_exit()里添加
按步写代码:
1首先声明一个定时器结构体:
static struct timer_list buttons_timer; //声明一个定时器结构体
2在init入口函数中初始化定时器结构体:
init_timer(&buttons_timer); //初始化:用init_timer对上一步声明的结构体初始化。主要初始化entry和base这两个参数,由内核完成,细节暂且不管。 /*成员.data未使用 不需要定时器到期时间,所以成员.expires无需初始化,默认为0,由于小于等于jiffies,会进入一次定时器超时函数*/ buttons_timer. function= buttons_timer_ function; add_timer(&buttons_timer); //激活定时器,从当前时刻开始计时。 注:以上3步可以用函数 setup_timer(time,func,data)代替,该函数实现赋值并初始化定时器,比手动设置更方便
3 在exit出口函数中删除定时器:
del_timer(&buttons_timer); //删除定时器
不是必须的:
buttons_timer.data= n //传递给buttons_timer_function的参数,可以不配置 buttons_timer.expires = jiffiers +10*Hz; //延时10s,可以先不配置,通过mod_timer修改这个参数
4在中断函数中重置定时器的值
struct pin_desc *irq_dev_id ; //定义全局变量获取dev_id 并修改中断服务函数: static irqreturn_t buttons_irq (int irq, void *dev_id) //中断服务函数 { irq_dev_id =(struct pin_desc *)dev_id; //获取引脚描述结构体 /*每产生一次中断,则更新定时器10ms超时,改变定时器的值,重新计时:如果在第5ms产生抖动,又一次触发中断,进入中断函数,再次调用 mod_timer给定时器重新赋值。则15m后进入timer_function。以此类推。按键中断服务程序处理(timer_function)是后一次抖动进入中断服函数的10ms之后。防止抖动。 */ mod_timer(&buttons_timer, jiffies+HZ/100); return IRQ_RETVAL(IRQ_HANDLED); }
注意: jiffies+HZ/100 也可以直接换成 jiffies + msecs_to_jiffies(10),更加方便
5当10ms超时到了,进入定时器超时函数,处理*irq_dev_id来判断是哪个按键按下的
static void buttons_timer_function(unsigned long data) //定时器超时处理函数:处理中断服务 { unsigned int pin_val=0; if(!irq_dev_id) //初始化时,由于定时器.expires成员=0,会进入一次,若irq_dev_id为0则退出 {printk("expires: timer out\n"); return ; } pin_val=s3c2410_gpio_getpin(irq_dev_id->pin); //获取按键值 if(pin_val) { /*按下 (下降沿),清除0x80*/ key_val=irq_dev_id->pin_status&0xef; } else { /*没有按下(上升沿),加上0x80*/ key_val=irq_dev_id->pin_status|0x80; } even_press=1; //退出等待队列 wake_up_interruptible(&button_wait); //唤醒 中断 kill_fasync(&button_async, SIGIO, POLL_IN); //发送SIGIO信号给应用层 }
6.测试效果
如下图所示,我们运行测试程序,来快速按下按键试试:
-
Zigbee-cc2530 笔记---Z-stack自定义按键(中断式)
2018-01-25 08:32:17Z-stack中提供了两种方式采集按键数据:轮询方式和中断方式。... 实现中断式按键处理的无线点灯 1.修改 SW_6 所在 IO 口 2. 修改边缘触发方式 3、修改中断一些相关标志位 4、修改HalKeyPollZ-stack中提供了两种方式采集按键数据:轮询方式和中断方式。轮询方式:每隔一定时间,检测按键状态,进行相应处理;中断方式:按键引起按键中断,进行相应处理。Zstack在默认情况下,使用轮询方式进行处理。
实现中断式按键处理的无线点灯
1.修改 SW_6 所在 IO 口
2. 修改边缘触发方式
3、修改中断一些相关标志位
4、修改HalKeyPoll()函数。
5、修改 hal_board_cfg.h 文件。
6、使能中断
7、修改中断处理函数
8、按键处理后,发送数据包 -
【JavaSE】多线程(7)_Lock体系中的可中断式获取锁、超时等待获取锁原理
2019-08-06 16:49:02本篇总结独占锁的另外两个特性:可中断式获取锁和超时等待获取锁 ~ 1 可中断式获取锁 可响应中断式锁需调用方法lock.lockInterruptibly(),而该方法其底层会调用AQS的acquireInterruptibly()方法,源码如下: ... -
STM32F103ZETX HAL学习——2.按键开灯(扫描式,中断式)
2020-03-01 19:24:36上一篇成功点亮的LED,本篇将学习GPIO的input和外部中断 说一次引脚的初始化配置 本次是PA4,PA5.各接一个LED,初始化为高电平,设置为低电平时点亮LED。 PA0是设置位外部中断模式...1.扫描式 原理重复查询input模式... -
stm32f407zet6初体验之GPIO按键判断之中断式
2021-02-18 15:29:07中断裸奔型代码效果2.延时处理型3.直接延时型总结 前言 快速的搞一波stm32,用的stm32f407zet6,不太常见的一个版本,买的平衡小车之家的板子,使用的stm32cubemx配置,keilv5编辑,使用swd烧录 项目持续更新再... -
STM32F103ZETX HAL学习——3.串口简单使用(简单的阻塞式发送,阻塞式接收,中断式接收)
2020-03-02 18:33:54中断式接收 这是串口1的中断回调函数 void HAL_UART_RxCpltCallback ( UART_HandleTypeDef * huart ) { if ( rxbuf [ 0 ] == 'u' , rxbuf [ 1 ] == 'p' ) { HAL_GPIO_WritePin ( GPIOA... -
单片机学习:中断式矩阵键盘(转载)
2010-11-22 14:36:00void key_down() interrupt 0//外部中断0有键按下,启动定时计数器 { EX0=0;// close TMOD&=0xf1; TH0=0x2e; TL0=0x00; ET0=1; TR0=1; } void timer0() interrupt 1 { TR0=0; Key_scan(); } void Key_... -
Lock锁详解(AQS,独占锁,可中断式获取锁,超时获取锁,理解ReentrantLock、ReentrantReadWriteLock,...
2019-05-07 18:27:433. 可中断式获取锁 4. 超时获取锁 5. 理解RenntrantLock 5.1 重入性的实现原理 5.2 公平锁与非公平锁 公平锁 VS 非公平锁 6. 理解读写锁ReentrantReadWriteLock 6.1 读写锁 6.2 写锁WriteLock--独占锁 6.2.1 写锁的...
-
鸿蒙系统Harmonyos源码架构分析-第1期第2课
-
C/C++反汇编解密
-
EaUS Video Editor(视频剪辑软件)官方中文版V1.6.8.53
-
python课件.rar
-
iperf3常用命令参数
-
2016通信中级互联网真题.pdf
-
FFmpeg4.3系列之16:WebRTC之小白入门与视频聊天的实战
-
MyBatisSelf.rar
-
图像分类预习知识笔记
-
MMM 集群部署实现 MySQL 高可用和读写分离
-
Amoeba 实现 MySQL 高可用、负载均衡和读写分离
-
request+response学习笔记
-
gexin-rp-sdk-http-4.1.1.0.rar
-
华为1+X——网络系统建设与运维(高级)
-
第3章-11 字符串排序 (20 分)
-
Liunx 优化思路与实操步骤
-
MySQL 数据库权限管理(用户高级管理和精确访问控制)
-
搭建etcd集群时,报错etcd: request cluster ID mismatch错误解决,只适用于新建etcd集群或无数据集群
-
_this2.$xxxis not a function
-
精通编译Makefile,Nina, 从底层uboot到Android