嵌入式系统之硬件总复习
快要期末考试啦,这几天在复习嵌入式系统,想着有好几天没有更新csdn了,就更新一篇嵌入式系统的文章!
本篇文章覆盖以下知识点:
- 如何亮灯
- 时钟周期如何计算
- printf函数如何使用
- 什么叫以查询的方式实现中断
- ATPCS规范是什么
- 中断响应流程
- pwm蜂鸣器启动方法
- 片外设备中断编程方法
同时,本文与我写的前几章文章一起看,效果会更好!
链接: 前几章复习文案.
文章目录
前言
码字不易,抽空写出文章更是不易。如果这篇文章帮助你明白了一些知识点,那就没有违背我写这篇文章的初心:
希望每一位同学都能通过考试。在日后学习上,我们的同学不是竞争对手,而是当成我们最亲密的战友。同时啊把这份善意传递给其他人。
本文开启了打赏模式,如果你觉得这篇文章对你帮助很大,麻烦你可以稍微打赏一下,拒绝用爱发电!
打赏一下,拒绝用爱发电!
打赏一下,拒绝用爱发电!
打赏一下,拒绝用爱发电!
提示:以下是本篇文章正文内容,如果错误,请联系我进行修改。
一、如何点亮LED灯?
这是教材第六章GPIO相关知识点,也就是GPIO编程实例!
点亮灯分为4个步骤:
- 查看硬件电路图,找出LED位于CPU的哪个引脚。
- 查看相关电路图,搞懂LED灯工作原理。
- 查看CPU手册,将相关位置初始化为0x1。
- 点亮LED灯,将gpj2dat 低4位 清0,con设置为输出的功能。
//con寄存器4位控制一个灯;
//dat寄存器控制相关引脚输出;
//pud一般是控制上拉/下拉电阻,一般不用
#define gpj2con *((volatile unsigned *)0xe020_0280)
#define gpj2dat *((volatile unsigned *)0xe020_0284)
void led_init(void){
//初始化con寄存器,先把所有位置清0,再赋值1;
gpj2con = gpj2con & ~(0xffff) | 0x1111;
//dat寄存器直接赋值1
gpj2dat = 0xf;
}
void led_on(char on){
//先把dat寄存器清0,然后 | 上on,决定打开哪些灯的开关
gpj2dat = gpj2dat & ~(0xff) | on;
}
期中考试试题就有一道类似的题目,当时是控制1,3位灯亮,然后下一秒换2,4位灯亮,然后循环亮。下面是代码,结合我之前说的,就明白代码意思啦!
//led
#define gpj2con *(unsigned*)0xe0200280
#define gpj2dat *(unsigned*)0xe0200284
void led_init( void );
void led_on( char on );
int on=0x5; (1 分)
void _start(void)
{
int i;
for(i=1;i<=20;i++)
{
led_on(on);
delay(500000);
on=on^0xf;
} (10分)
void led_init( )
{
gpj2con = gpj2con & ~0xffff | 0x1111;
gpj2dat = 0xf;
} (5分)
void led_on( char on )
{
gpj2dat = gpj2dat & ~0xf | ~on;
} (5分)
void delay( int t)
{
for(;t-- ; );
}
二、时钟周期的计算
这个地方建议查看开发板说明手册 P355页。
根据0xE010_0108处的地址值确定PDIV,MDIV,SDIV的值。
见下图步骤
三、如何使用printf函数
其实,我刚开始也不知道如何调用printf函数,怎么才能打印,后来问了老师,老师给我说了printf函数原型,才明白我们要如何写printf函数。
先上代码:
int (* myprintf)(char *,...)=(int (*)(char *,...))0x2fd17b18;
myprintf是我们的函数名,注意,不要使用print还是printf,我忘记了,因为会和开发板本身自带的一个函数名字起冲突,所以我一般习惯性用myprintf做打印函数名。
在实验期末考试中,我们如何打印“hello world!”,其实只需这样一段代码:
int (*myprintf)(char *,...)=(int (*)(char *,...))0x2fd17b18;
//不带参数的myprintf函数,带参数的话,就按照我们常用的c语言的printf用即可。
void __attribute__((interrupt)) wdt_isr(void)
{
myprintf("hello world!");
clear_int();
}
四、以查询的方式实现中断
这一块主要讲2个函数,先把所要用到的地址放出来。
#define gph3con *((volatile unsigned*)0xe0200c60)
#define gph3dat *((volatile unsigned*)0xe0200c64)
#define gph3pud *((volatile unsigned*)0xe0200c68)
con寄存器
date寄存器和pud寄存器
代码部分:
#define gph3con *((volatile unsigned*)0xe0200c60)
#define gph3dat *((volatile unsigned*)0xe0200c64)
#define gph3pud *((volatile unsigned*)0xe0200c68)
//将con寄存器配置成输入的功能,这是按键初始化
void key_init(void)
{
gph3con=gph3con&~(0xffff);
}
//如何检测那个键被按下了呢?
//如果第一个键被按下了
if((gph3dat & (0x1))==0)
{
while(!(gph2dat&(0x1)));
return 1;
}
//如果第二个按键被按下了
if((gph2dat & (0x1))==0)
{
while(!(gph2dat&(0x1)));
return 1;
}
五、ATPCS规范
没有什么比标准答案更好的材料了,直接背标准答案!!!
- 子程序通过寄存器r0-r3 来传递参数,如果参数多于4个,多出的部分用堆栈来传递,r0-r3不用恢复。(1分)
- R4-r11用来保存局部变量,使用前保存这些寄存器的值,子程序退出时要恢复这些寄存器(1分)
- r12 常用保存sp (1分)
- r13 用途堆栈指针,记作sp (1分)
- r14用作链接寄存器,用来保存程序的返回地址,记叙lr (2分)
- r15 即pc,用户程序计数器,不作其他用途 (2分)
7.函数返回值保存在r0中。 (2分)
调用printf函数过程:
1)将返回地址入lr (2分)
2) 将字符串“x=%d,y=%d,z=%d,s=%d”地址入r0 (3分)
3)x值入r1,y值入r2,z值入r3,s值入栈 (2分)
4) 跳转到0x2fdb1718处执行程序 (3分)
六、中断响应流程
我理解的中断响应过程指的是WDT看门狗这个实验!
这个我觉得应该没必要再说了!期中考试考这个!期末考试考这个!应该都会了!
我就直接把我以前写的那篇wdt看门狗文章链接丢在这,然后看一下就行了!
链接: WDT看门狗实验.
七、pwm蜂鸣器
蜂鸣器应该是我们做的倒数第二个实验了!!!我自己的话有一个点不太确定,就是1200,我个人的想法是:根据题目给的,如果有同学知道1200怎么来的,请告诉我!!!万分感谢!!!
正式开始说明:
蜂鸣器启动步骤:
- 初始化时钟(分频器、选频器);
- 初始化tchtb,tcmpb,调整占空比;
- 停止auto-reload,使能manual update
- 使能auto-reload,清除manual update
具体步骤见代码注释,边写代码边说明,我知道的我都会说,emmm我也很菜的!!!我也靠不住,呜呜呜。
1、初始化时钟频率(分频器,选频器)
#define gpd0con *(volatile unsigned*)0xe02000a0
gpd0con = gpd0con & ~0xf|0x2;//配置成time0
//设置预分频器的值
#define tcfg0 *(volatile unsigned*)0xe2500000
tcfg0 = 一个不超过255的整数;
//设置选频器的值
#define tcfg1 *(volatile unsigned*)0xe2500004
tcfg1 = 0000 || 0001 || 0010 || 0011 || 0100 || 0101; //选一个即可,见下面的说明
2、初始化tcntb,tcmpb的值
#define tcntb0 *(volatile unsigned*)0xe250000c
#define tcmpb0 *(volatile unsigned*)0xe2500010
tcntb0 = 150;
tcmpb0 = 50;
备注:占空比= 1 - (tcmpb/tcntb)
#define tcon *(volatile unsigned*)0xe2500008
3、停止auto-reload,使能manual update
tcon = tcon & ~(0x1<<3) | (0x1<<1);
4、使能auto-reload,清除manual update,并启动蜂鸣器
tcon = tcon & ~(0x1<<1)|(0x1<<3) | 0x1;
预分频器
选频器
tcon=0xe250_0008
还要在设置这个地方,设置1,允许中断
八、片外设备中断处理
这个指的是实验10。
步骤:
初始化片外设备中断控制器---------->初始化中断控制器----------->开cpu中断
/ about vic0
//[27]=0 select IRQ
#define vic0intselect *(volatile unsigned*)0xf200000c
//[27]=1 enable wtd int
#define vic0intenable *(volatile unsigned*)0xf2000010
// contains isr
#define vic0vectaddr16 *(volatile unsigned*)0xf2000140
//ext_int_2
//[0:15]=0x3333 rising edge triggered
#define ext_int_2_con *(volatile unsigned*)0xe0200e08
//[0:31]=0x80808080 delay flt
#define ext_int_2_fltcon0 *(volatile unsigned*)0xe0200e90
//[0:3]=0x0 enable interrupt
#define ext_int_2_mask *(volatile unsigned*)0xe0200f08
void vic0_init( void )
{
vic0intselect = vic0intselect & ~(0x1<<16);
vic0intenable = vic0intenable | (0x1<<16);
vic0vectaddr16 = key_isr;
}
void ext_int_2_init( void )
{
ext_int_2_con = ext_int_2_con & ~0xffff | 0x3333;
ext_int_2_fltcon0 = 0x80808080;
ext_int_2_mask = ext_int_2_mask & ~0xf;
}
最后,很感谢大家的观看!其实呢,我很想净化 班级内卷的氛围,人人都在偷偷学习,真的少了很多快乐。
社会达尔文主义不能拯救你,内卷你跳不出来的,我也没办法跳出来,但是我们可以尝试不要那么内卷,当我们陷入内卷的氛围中,社会达尔文主义已经让你丧失了一个作为人最基本的尊严!我们是人,不是兽。身边的小伙伴不是我们的竞争对手,而是我们最亲密的战友!!!
去拥抱我们身边的每一个人吧,带着我们的善意,传递下去!
总结
嵌入式系统硬件部分就说到这里,系统的过了一遍。祝各位取得好成绩!
如果你觉得看的很爽,那就点点赞,打赏一波!
拒绝白嫖伸手党!!!
拒绝白嫖伸手党!!!
拒绝白嫖伸手党!!!