基于友善之臂ARM-ContexA9-ADC驱动开发

简介: 基于友善之臂ARM-ContexA9-ADC驱动开发

版权声明:本文为博主原创文章,如有需要,请注明转载地址:http://blog.csdn.net/morixinguan。若是侵权用于商业用途,请联系博主,否则将追究责任

ADC,就是模数转换器,什么是模数转换器?

模数转换器,在电子技术中即是将模拟信号转换成数字信号,也称为数字量化。

当然还有一种叫DAC,就是数模转换,意思相反,即是将数字信号转换成模拟信号。

在友善之臂ARM-contexA9这款开发板上的4412芯片本身就自带了一个ADC的接口,我们来看看基本介绍:

0.jpg

数据手册开篇介绍了这么多,最有用的一句话:精度10位或12位CMOS模数转换器(ADC)包括多路模拟输入。灵敏度为1M,一共有4路输入,支持较低的电源模式等。

接下来我们还是跟以前一样:

1、先看电路原理图:


640.png

640.png

从原理图和核心板上可以看出可调电阻的IO对应数据手册的是AIN[0]。

640.jpg

2、看数字手册相关的寄存器

(1)ADC控制寄存器

640.jpg

寄存器的地址为:0x126C0000

在这里,我们要如何配置呢?

[0] 第0位:判断A/D转换有没有开始

[2] 第2位:配置模式位(正常的,标准的,我们这里选择默认为0)

[6:13]第6~13位:这里要配置预分频系数,我们配置为49,对应的公式就是:ADCCLK=PCLK/(49+10)=100MHZ / 50 =2MHZ

[14]第14位:选择使能预分频,写1到这个位去就可以了

[15]第15位:判断A/D转换结束了没有

[16]第16位:设置转换的精度(10或者12,自己选)

(2)ADC数据寄存器

640.png

基地址:0x126C000C

[11:0] 第0~11位:ADC转换的数据

(2)ADC通道选择寄存器

640.jpg

基地址:0x12C001C

ADCMUX[0:3]:这里我们配置为0000,也就是通道0

3、写代码

config.h

<span style="font-size:18px;">#ifndef __CONFIG_H__  
#define __CONFIG_H__
#define udelay  ((void (*)(unsigned int ))0x43e25e88)     //定义udelay在uboot中的地址,这样我们就可以使用这个函数
#define print   ((int (*)(const char *, ...))0x43e11434)  //定义printf在uboot中的地址
typedef unsigned int u32;  
typedefvolatile u32 v32;  
//设置位
#define set_one(reg, bit)   \
                ((*(v32 *)reg) |= (1<<bit))  
#define set_zero(reg, bit)  \
                ((*(v32 *)reg) &= (~(1<<bit)))  
#define set_bit(reg, bit, val)  \
                (*(v32 *)reg = (((*(v32 *)reg) & (~(1<<bit))) | (val << bit)))  
#define set_2bit(reg, bit, val) \
                (*(v32 *)reg = (((*(v32 *)reg) & (~(3<<bit))) | (val << bit)))  
#define set_nbit(reg, bit, n, val)  \
                (*(v32 *)reg = (((*(v32 *)reg) & (~( ((1<<n)-1) <<bit))) \  
                                    | (val << bit)))  
#define set_val(reg, val)   \
                ((*(v32 *)reg) = val)  
#define get_bit(reg, bit)   \
                (((*(v32 *)reg) & (1<<bit)) >> bit)  
#define get_2bit(reg, bit)  \
                (((*(v32 *)reg) & (3<<bit)) >> bit)  
#define get_nbit(reg, bit, n)   \
                (((*(v32 *)reg) & (((1<<n)-1) <<bit)) >> bit)  
#define get_val(reg)        \
                (*(v32 *)reg)  
#endif</span>
<span style="font-size:18px;">#ifndef __CONFIG_H__
#define __CONFIG_H__
#define udelay  ((void (*)(unsigned int ))0x43e25e88)     //定义udelay在uboot中的地址,这样我们就可以使用这个函数
#define print ((int (*)(const char *, ...))0x43e11434)  //定义printf在uboot中的地址
typedef unsigned int u32;
typedef volatile u32 v32;
//设置位
#define set_one(reg, bit) \
        ((*(v32 *)reg) |= (1<<bit))
#define set_zero(reg, bit)  \
        ((*(v32 *)reg) &= (~(1<<bit)))
#define set_bit(reg, bit, val)  \
        (*(v32 *)reg = (((*(v32 *)reg) & (~(1<<bit))) | (val << bit)))
#define set_2bit(reg, bit, val) \
        (*(v32 *)reg = (((*(v32 *)reg) & (~(3<<bit))) | (val << bit)))
#define set_nbit(reg, bit, n, val)  \
        (*(v32 *)reg = (((*(v32 *)reg) & (~( ((1<<n)-1) <<bit))) \
                  | (val << bit)))
#define set_val(reg, val) \
        ((*(v32 *)reg) = val)
#define get_bit(reg, bit) \
        (((*(v32 *)reg) & (1<<bit)) >> bit)
#define get_2bit(reg, bit)  \
        (((*(v32 *)reg) & (3<<bit)) >> bit)
#define get_nbit(reg, bit, n) \
        (((*(v32 *)reg) & (((1<<n)-1) <<bit)) >> bit)
#define get_val(reg)    \
        (*(v32 *)reg)
#endif</span>

adc.h

<span style="font-size:18px;">#ifndef __ADC_H__  
#define __ADC_H__
#define ADCCON 0x126C0000     //ADC控制寄存器
#define ADCDAT 0x126C000C     //ADC数据寄存器
#define ADCMUX 0x126C001C     //ADC通道寄存器
#define CLRINTADC   0x126C0018  //清除ADC中断
#endif</span>
<span style="font-size:18px;">#ifndef __ADC_H__
#define __ADC_H__
#define ADCCON 0x126C0000     //ADC控制寄存器
#define ADCDAT 0x126C000C     //ADC数据寄存器
#define ADCMUX 0x126C001C     //ADC通道寄存器
#define CLRINTADC 0x126C0018  //清除ADC中断
#endif</span>

adc.c

<span style="font-size:18px;">#include <adc.h>  
#include <config.h>
void select_mux(void)  
{  
    set_nbit(ADCMUX, 0, 4, 0x0);   //设置通道为通道0
}  
void adc_init(void)  
{  
    set_val(ADCCON, ((1<<16)|(1<<14)|(49<<6)));   //按照数据手册参数来配置adc控制寄存器的初始化部分
}  
void adc_start(void)  
{  
    set_one(ADCCON, 0);   //adc转换开始的配置,默认参数为0
}  
int adc_wait_flag(void)  
{  
    return get_bit(ADCCON, 15);<span style="white-space:pre"> </span>//AD转换是否成功
}  
int adc_data(void)  
{  
    return get_nbit(ADCDAT, 0, 12); //获取ADC数据
}     
void clear_adc(void)  
{  
    set_val(CLRINTADC, 0);<span style="white-space:pre">  </span>//清ADC
}</span>  
<span style="font-size:18px;">#include <adc.h>
#include <config.h>
void select_mux(void)
{
  set_nbit(ADCMUX, 0, 4, 0x0);   //设置通道为通道0
}
void adc_init(void)
{
  set_val(ADCCON, ((1<<16)|(1<<14)|(49<<6))); //按照数据手册参数来配置adc控制寄存器的初始化部分
}
void adc_start(void)
{
  set_one(ADCCON, 0);   //adc转换开始的配置,默认参数为0
}
int adc_wait_flag(void)
{
  return get_bit(ADCCON, 15);<span style="white-space:pre"> </span>//AD转换是否成功
}
int adc_data(void)
{
  return get_nbit(ADCDAT, 0, 12); //获取ADC数据
} 
void clear_adc(void)
{
  set_val(CLRINTADC, 0);<span style="white-space:pre">  </span>//清ADC
}</span>

main.c

<span style="font-size:18px;">#include <config.h>  
#include <adc.h>
int main(void)  
{     
    //设置ADC通道为通道0
    select_mux();  
    //adc初始化
    adc_init();  
    //adc转换开始
    adc_start();  
    while(1)  
    {  
        //判断是否已经转换
        if(adc_wait_flag())  
        {  
            //打印相应的数据
            print("data = %d\n",adc_data());  
            //重新adc转换开始
            adc_start();  
        }  
    }     
    return 0;  
}</span>  
<span style="font-size:18px;">#include <config.h>
#include <adc.h>
int main(void)
{ 
  //设置ADC通道为通道0
  select_mux();
  //adc初始化
  adc_init();
  //adc转换开始
  adc_start();
  while(1)
  {
    //判断是否已经转换
    if(adc_wait_flag())
    {
      //打印相应的数据
      print("data = %d\n",adc_data());
      //重新adc转换开始
      adc_start();
    }
  } 
  return 0;
}</span>

4、makefile略

5、观察结果

先让uboot启动

640.jpg

然后用dnw下载程序:

640.jpg

最后旋转电阻观察数据变化:

640.jpg

目录
相关文章
|
7月前
|
算法 编译器 Linux
【Qt4 部署】ARM系统上使用Qt 4 进行开发的QWS 等环境变量部署
【Qt4 部署】ARM系统上使用Qt 4 进行开发的QWS 等环境变量部署
138 0
|
4月前
|
编解码 安全 Linux
基于arm64架构国产操作系统|Linux下的RTMP|RTSP低延时直播播放器开发探究
这段内容讲述了国产操作系统背景下,大牛直播SDK针对国产操作系统与Linux平台发布的RTMP/RTSP直播播放SDK。此SDK支持arm64架构,基于X协议输出视频,采用PulseAudio和Alsa Lib处理音频,具备实时静音、快照、缓冲时间设定等功能,并支持H.265编码格式。此外,提供了示例代码展示如何实现多实例播放器的创建与管理,包括窗口布局调整、事件监听、视频分辨率变化和实时快照回调等关键功能。这一技术实现有助于提高直播服务的稳定性和响应速度,适应国产操作系统在各行业中的应用需求。
141 3
|
7月前
|
Linux 开发工具 芯片
玩转 PI 系列 - 如何在 Rockchip Arm 开发板上安装 Docker Tailscale K3s Cilium?
玩转 PI 系列 - 如何在 Rockchip Arm 开发板上安装 Docker Tailscale K3s Cilium?
ARM6818开发板画任意矩形,圆形,三角形,五角星,6818开发板画太极,画五星红旗(含码源与思路)
ARM6818开发板画任意矩形,圆形,三角形,五角星,6818开发板画太极,画五星红旗(含码源与思路)
564 0
|
7月前
|
存储 Ubuntu Linux
ARM-Linux开发与MCU开发的不同之处分析
ARM-Linux开发与MCU开发的不同之处分析
75 0
|
Linux C++
基于ARM-contexA9-Linux驱动开发:如何获取板子上独有的ID号
基于ARM-contexA9-Linux驱动开发:如何获取板子上独有的ID号
137 0
|
缓存 C++
基于ARM-contexA9-蜂鸣器pwm驱动开发
基于ARM-contexA9-蜂鸣器pwm驱动开发
118 0
基于ARM-contexA9蜂鸣器驱动开发
基于ARM-contexA9蜂鸣器驱动开发
107 0
|
算法 物联网 测试技术
开发一个arm固件加载基址定位器
最近入坑iot,涉及很多芯片固件的逆向。但是这些固件很多时候都不是标准二进制格式,也就是说丢进ida,识别不出架构和指令集。架构和指令集可以查芯片的文档,但是加载基址还没法确定,这个靠自己去定位,再配置ida。人工做这个工作太累,而我又是懒狗,所以自动化这一过程不香吗?
|
23天前
|
机器学习/深度学习 弹性计算 人工智能
阿里云服务器架构有啥区别?X86计算、Arm、GPU异构、裸金属和高性能计算对比
阿里云ECS涵盖x86、ARM、GPU/FPGA/ASIC、弹性裸金属及高性能计算等多种架构。x86架构采用Intel/AMD处理器,适用于广泛企业级应用;ARM架构低功耗,适合容器与微服务;GPU/FPGA/ASIC专为AI、图形处理设计;弹性裸金属提供物理机性能;高性能计算则针对大规模并行计算优化。