操作流程:
一、实现一个led亮灯
(1)GPIO:可编程的输入输出引脚
每一组io都有一个寄存GP*CON控制引脚作用,每个io都有2个位,控制引脚作用
每一组io都有一个寄存GP*DAT控制引脚数据,每个io都有1个位,控制引脚数据
(2)如图:
在原理图中找到控制led的引脚端口,进而对引脚进行相应的输出配置。
从下图可以看出当引脚为低电平时,LED会被点亮,所以需要寻找对应的nLED_1(对应的GPIO口)
如下图,led对应的寄存器时GPB寄存器,
因此使能GPBCON ,使GPBDA的第五位输出低电平/
再从下图中,将GPB的第十位和第十一位设置为01(输出模式)
代码如下:
volatile的用法
在C语言中,
volatile
是一个类型限定符,它的主要作用是告诉编译器,它所修饰的变量的值可能会在程序执行期间被意外地改变(通常是由程序外部的因素导致的),因此编译器不应该对这些变量进行优化,包括不应该将这些变量的值缓存到寄存器中,而应该每次访问时都从内存中重新读取其值。volatile
的用法主要包括以下几个方面:
- 防止编译器优化
编译器在编译代码时,为了提高程序的执行效率,会对代码进行优化,包括将一些常量或变量的值缓存到寄存器中以便快速访问。但在多线程编程、硬件交互等场景中,变量的值可能会被外部因素(如其他线程、硬件设备等)意外地改变。如果编译器对这些变量进行了优化,就可能导致程序无法正确地反映这些外部变化,进而产生错误。通过使用
volatile
关键字,可以阻止编译器对这些变量进行优化,确保每次访问时都能从内存中读取到最新的值。
- 保证内存可见性
在多线程编程中,一个线程对共享变量的修改需要能够被其他线程所感知,这就是所谓的内存可见性。如果编译器对共享变量进行了优化(如缓存到寄存器中),就可能导致其他线程无法及时感知到该变量的最新值。通过使用
volatile
关键字,可以确保每个线程在访问共享变量时都能从内存中读取到最新的值,从而保证内存的可见性。
- 嵌入式系统编程
在嵌入式系统编程中,经常需要直接与硬件进行交互,包括读取硬件寄存器的值、向硬件寄存器写入数据等。由于硬件寄存器的值可能会被外部设备或中断服务例程等意外地改变,因此需要使用
volatile
关键字来修饰这些寄存器变量,以确保每次访问时都能从硬件寄存器中读取到最新的值。
- 调试和性能分析
在某些情况下,为了关闭编译器的某些优化以便更好地进行调试或性能分析,也可以使用
volatile
关键字。通过将某个变量声明为volatile
,可以确保编译器在编译时不会对该变量进行优化,从而保留更多的程序原始信息供调试或性能分析使用。
二、实现流水灯
类似的添加延时函数即可实现蜂鸣器的效果。
cs
extern int asm_add(int x, int y);
#define WTCON *(volatile unsigned long *)0x53000000UL
#define GPBCON *(volatile unsigned long *)0x56000010UL //11:10 0b 01
#define GPBDAT *(volatile unsigned long *)0x56000014UL
void c_deal_swi(unsigned int num)
{
switch (num)
{
case 1:break;
case 2:break;
case 3:break;
default:
break;
}
}
//延时函数
void delay(int i)
{
while(i--);
}
void led_init(void)
{
//配置GDB5引脚功能为输出
GPBCON &= ~(0xff << 10);
GPBCON |= (0x55 << 10);
//将GDB5引脚电平置高
GPBDAT |= (0x55 << 5);
}
void led_on(unsigned int i)
{
//将GDB5引脚设置为低电平
GPBDAT &= ~(1 << 5<<(i-1));
}
void led_off(unsigned int i)
{
//将GDB5引脚设置为高电平
GPBDAT |= (1 << 5<<(i-1));
}
int main(void)
{
// led_init();
int i =0;
WTCON = 0x0; //看门狗置0
while(1)
{
led_init();
for(i=1;i<5;i++)
{
led_on(i);
delay(30000);
led_off(i);
}
}
return 0;
}
三、实现按健控制等
(1)设置GPIO为输入模式
从下图 可以看出当K1被按下,EINT8被设置为输入模式,通过该引脚可以判断按键是否被按下;
cs
extern int asm_add(int x, int y);
int myadd(int a, int b)
{
int c = asm_add(a, b);
return c;
}
void c_deal_swi(unsigned int num)
{
switch(num)
{
case 1:break;
case 2:break;
case 3:break;
default:break;
}
}
#define GPBCON *(volatile unsigned long *)0x56000010UL
#define GPBDAT *(volatile unsigned long *)0x56000014UL
#define GPFCON *(volatile unsigned long *)0x56000050UL
#define GPFDAT *(volatile unsigned long *)0x56000054UL
#define GPGCON *(volatile unsigned long *)0x56000060UL
#define GPGDAT *(volatile unsigned long *)0x56000064UL
#define WTCON *(volatile unsigned long *)0x53000000UL
#define WTCNT *(volatile unsigned long *)0x53000008UL
void watchdog_close(void)
{
WTCON = 0x8021;
WTCON &= ~0x1;
}
void watchdog_init(void)
{
WTCON = 0x8021;
}
void watchdog_feed(void)
{
WTCNT = 0x8000;
}
void button_init(void)
{
GPGCON &= ~(0x3f << 8);
GPFCON &= ~0x3;
}
void led_init(void)
{
GPBCON &= (~(0xff << 10));
GPBCON |= (0x55 << 10);
GPBDAT |= 0xf << 5;
}
void delay(unsigned long us)
{
while(us--)
;
}
void led_on(unsigned int n)
{
//GPB5Òý½ÅµçƽÖõÍ
GPBDAT &= ~(1 << (n + 4));
delay(30000);
}
void led_off(unsigned int n)
{
GPBDAT |= (1 << (n + 4));
delay(30000);
}
void led_off_all(void)
{
GPBDAT |= (0xf << 5);
}
/*
void delay_ms(unsigned long ms)
{
unsigned int i;
while(ms--)
{
for(i = 0; i < 1200; i++)
{
}
}
}
*/
void button_led1(void)
{
unsigned long tmp,tmp1,tmp2,tmp3;
while(1)
{
tmp = GPGDAT & 0x1;
tmp1 = GPFDAT & 0x1 <<4;
tmp2 = GPFDAT & 0x1 <<5;
tmp3 = GPFDAT & 0x1 <<6;
if(tmp == 0)
{
GPBDAT &= ~(1 << 5);
delay(500);
}
else if(tmp1 == 0)
{
GPBDAT &= ~(1 << 6);
delay(500);
}
else if(tmp2 == 0)
{
GPBDAT &= ~(1 << 7);
delay(500);
}
else if(tmp3 == 0)
{
GPBDAT &= ~(1 << 8);
delay(500);
}
else
{
led_off_all();
}
}
}
int main(void)
{
int i = 0;
watchdog_close();
led_init();
button_init();
/*while(1)
{
i = 4;
while(i)
{
led_on(i);
led_off(i);
i--;
watchdog_feed();
}
}*/
button_led1();
}
三、时钟
pwm定时器