使用开发板:FS4412,Soc:Exynos内核型号4412:cortex-A9,架构:armv7; 文件:开发板原理图,Soc数据手册; 环境:文件编写与编译:Linux;下载:超级终端hypertrm;串口下载 编译器:交叉编译器arm
文章目录
-
- 一 看门狗定时器
-
- 1 看门狗定时器是什么?
-
- 1.1 什么是门狗?
- 1.2 看门狗有什么用?
- 2 使用门狗
-
- 2.1 查硬件电路
- 2.2 查寄存器
- 2.3 编程
- 二 PWM驱动无源蜂鸣器
-
- 1 粗略提一点概念
- 2 查硬件电路
- 3 查寄存器
- 4 编程
- 三 ADC的简单使用
-
- 1 简单描述
- 2 查原理图
- 3 查寄存器
- 4 编程
一 看门狗定时器
1 看门狗定时器是什么?
1.1 什么是门狗?
如果我们按照教科书来学习,里面的概念就足够我们吃一天了。当我们做发展时,我们应该注意一个简短而快速的。不要把那些无用的东西整理出来。如果你默地写下教科书上的概念,你可以写下代码吗?严肃的人仍然阅读教科书。 还有,不要整整喂狗。本来学习就够麻烦了,要想狗,还要联系定时器。你累吗?
1.2 看门狗有什么用?
(1) 到时候复位不是闹事吗? 啊,我在时间到了之前就把定时器的值改了,不会到触发复位的条件,好吧。 (2) 怎么改? 我在时间到来之前把定时器改成了初始值,也就是说,让它重新开始计时,我也定期改变,让定时器一直计时,但不能达到设定的时间,也不会重置。 (3) 实现了哪些功能: 跑飞:就是程序不知道跑到哪里去了,不受控制,不做任何相应,卡死也是一种跑飞; (4) 对于那些在没有监控的情况下运行的程序,不知道什么时候可能异常,不能及时复位;现在有了看门狗,设定时间计时;定期恢复用户代码中的计数值,防止复位程序;当用户程序异常运行时,离开用户程序的看门狗计时器到达设定值,恢复正常运行状态; (5) 因此,看门狗的到点复位是程序正常运行时的癌症,程序运行时的救星;
2 使用门狗
2.1 查硬件电路
看门狗定时器是soc工作时不需要引脚:
2.2 查寄存器
如图所示,8-15位设置第一系列分频,3-4位选择第二级分频,第五位控制看门狗的开关,第二位控制是否中断,第0位设置到达时间是否复位,即可选择时间中断或时间重启。这一次,我们只选择重启; 从第一个框图可以看出,第0-15位设置计数器的最大值wdt是递减计时器;
2.3 编程
下图的程序中,开启了看门狗但是没用复原操作,只放了流水灯,现象为到达设定时间后程序复位,由于程序是烧录到内存中的,所以直接复位导致程序丢失;流水灯全灭无现象;
/* main.c */ #include "led.h" #include "wdt.h" void init() {
led_init(); wdt_init(); } int main() {
init(); while(1) {
streamled();///流水灯; } return 0; }
恢复操作添加到下图的主程序中,程序不再复位,流水灯一直在运行;
/* main.c */ #include "led.h"#include "wdt.h"
void init()
{
led_init();
wdt_init();
}
int main()
{
init();
while(1)
{
streamled();
delay();
delay();
delay();
wdt_re;//复原操作
}
return 0;
}
/* wdt.c */
#include "wdt.h"
void wdt_init()
{
//设置一级250分频,
WTCON&=~(0xff<<8);
WTCON|= (249 <<8);
//设置二级128分频;
WTCON&=~(0x3<<3);
WTCON|= (0x3<<3);
//分频后频率为3125hz;计数器值为15625,即定时5s;
//设置计时器初值;
wdt_re;
//使能reset
WTCON|=1;
//开启
WTCON|=1<<5;
}
/* wdt.h */
#ifndef _WDT_H_
#define _WDT_H_
#define uint unsigned int
#define uchar unsigned char
#define WTCON *((volatile uint *)0x10060000)
#define WTCNT *((volatile uint *)0x10060008)
#define WT_VALUE 15625
#define wdt_re WTCNT=WT_VALUE
void wdt_init();
#endif
/* led.c */
#include "led.h"
void delay()
{
int i=0xfffff;
while(i--);
}
void led_init()
{
//设置GPX1_0引脚为输出功能,将GPX1CON的0-3位设置为0x01
GPX1CON &= ~(0xf << 0); //将0-3位清0
GPX1CON |= (0x1 << 0); //将0-3设置为0x1
GPF3CON &= ~(0xff << 16); //将16-23位清0
GPF3CON |= (0x11 << 16); //将16-23设置为0x11
}
void streamled()
{
led3on;
delay();
led3of;
delay();
led4on;
delay();
led4of;
delay();
led5on;
delay();
led5of;
delay();
}
/* led.h */
#ifndef _LED_H_
#define _LED_H_
#define GPX1CON *((volatile unsigned int *)0x11000c20)
#define GPX1DAT *((volatile unsigned int *)0x11000c24)
#define GPF3CON *((volatile unsigned int *)0x114001e0)
#define GPF3DAT *((volatile unsigned int *)0x114001e4)
//设置GPX1_0引脚输出1
#define led3on GPX1DAT |= (0x1 << 0) //将第0位设置为1
#define led3of GPX1DAT &=~(0x1 << 0) //将第0位清0
#define led4on GPF3DAT |= (0x1 << 4)
#define led4of GPF3DAT &=~(0x1 << 4)
#define led5on GPF3DAT |= (0x1 << 5)
#define led5of GPF3DAT &=~(0x1 << 5)
void led_init();
void delay();
void streamled();
#endif
二 PWM驱动无源蜂鸣器
1 粗略提一点概念
上图中占空比就是200/1000=0.2或者说20%; 用通用的定时器可以实现PWM的波形输出,但是不低级的芯片都有专门的PWM外设,只需要设置寄存器就可以产生PWM波形; 无源蜂鸣器需要一个频率波来实现振动,才能发声;(有源蜂鸣器只需要通电就可以响)
2 查硬件电路
引脚是GPD0_0, 用的是pwm0;
3 查寄存器
设置为定时器输出; 设置第一级分频; 设置第二级分频; 控制寄存器,这里只用到低4位;第0位是开启和关闭,第1位进行TCNTB和TCMPB的更新,第2位选择是否翻转电平,第3位设置是否自动重载计数;
4 编程
/* main.c */
#include "led.h"
#include "pwm.h"
int main()
{
led_init();
beep_init();
pwm_init();
while(1)
{
streamled();//流水灯;
pwm_set(20);//设置占空比
pwmon();//开启
delay();//响这么久
pwmof();//关闭
}
return 0;
}
/* pwm.c */
#include "pwm.h"
void beep_init()
{
GPD0CON&=~0XF;
GPD0CON|=0X2;
}
void pwm_init()
{
//设置GPD0_0为pwm输出
GPD0CON = GPD0CON & ~(0XF << 0) | (0X2 << 0);
//分频 -->200000HZ
TCFG0 = TCFG0 & ~0XFF | 150;
TCFG1 = TCFG1 & ~0XF | 0X1;
//设置计数器寄存器的值
TCNTB0 = 100;
//设置比较寄存器的值(占空比)
TCMPB0 = 50;
}
void pwmon()
{
//手动更新计数器和比较寄存器的值
TCON = TCON & ~0XF | 0XA;
//启动定时器
TCON = TCON & ~0XF | 0X9;
}
void pwmof()
{
TCON&=~0x1;
}
void pwm_set(int a)
{
TCMPB0=a;
TCON&=~0xf;
TCON|=0xa;
}
#ifndef _LED_H_
#define _LED_H_
#define GPD0CON *((volatile unsigned int *)0x114000a0)
#define TCFG0 *((volatile unsigned int *)0x139D0000)
#define TCFG1 *((volatile unsigned int *)0x139d0004)
#define TCON *((volatile unsigned int *)0x139d0008)
#define TCNTB0 *((volatile unsigned int *)0x139d000c)
#define TCMPB0 *((volatile unsigned int *)0x139d0010)
void pwm_init();
void beep_init();
void pwm_set(int);
void pwmon();
void pwmof();
#endif
三 ADC的简单使用
1 简单描述
在学习初期,ADC一般用来读电压,也就是开发板上电位器的电压,概念和原理没啥好说的,只要会配置寄存器,读到电压值即可,就已经能够应付初期大部分的代码任务,在程序中把电压值和其他模块联合起来实现用电位器控制的效果;本次来看使用一路ADC读一个电位器电压的程序示例; 大致流程为: 1、分频 2、设置分辨率 3、开启转换 4、读转换结果
2 查原理图
3 查寄存器
第0位开启adc转换,第1位通过读操作来启动转换,第2位设置工作模式或者省电模式,6-13位设置分频,14位设置是否使能分频,15位是转换完成标志,16位设置10bit或者12bit;
adc数据寄存器,从这里读; adc通路选择
4 编程
/* main.c */
#include "led.h"
#include "pwm.h"
#include "adc.h"
void delay()
{
int i=0xfffff;
while(i--);
}
int main()
{
led_init();
beep_init();
pwm_init();
adc_init();
while(1)
{
streamled();
adc_ctrl(adc_read());//在这里控制pwm的占空比
pwmon();
delay();
pwmof();
}
return 0;
}
/* adc.c */
#include "adc.h"
void adc_init()
{
ADCMUX=3;//选择通道3
ADCCON&=~(1<<16);
ADCCON|= (1<<14);
ADCCON&=~(0xff<<6);
ADCCON|= (19<<6);
ADCCON&=~(1<<2);
ADCCON&=~(1<<1);
}
int adc_read()
{
ADCCON|=0X1;//开启转换;
while(!(ADCCON&(1<<15)));//等待转换完成;
return (ADCDAT&0x3ff);//返回读到的10bit结果;
}
void adc_ctrl(int data)
{
pwm_set(data/10);//10bit最大为1024;data/1024就是现在电位器电压值所占最大电压的比,乘以100就能用来当作占空比,大约等于data/10;
}
/* adc.h */
#ifndef _ADC_H_
#define _ADC_H_
#include "pwm.h"
#define ADCCON *((volatile unsigned int *)0x126c0000)
#define ADCDAT *((volatile unsigned int *)0x126c000c)
#define ADCMUX *((volatile unsigned int *)0x126c001c)
void adc_init();
int adc_read();
void adc_ctrl(int);
#endif