ARM day7 day8 UART串口、PWM蜂鸣器、WDT看门狗、ADC数模转换

一、串口编程

1.看原理图

|---------------------------|
| GPA1_0: RXD2 GPA1_1: TXD2 |

2.看芯片手册

|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1)对外设置 (GPIO) GPA1CON: 0x11400020 3:0->0x2(RXD2) 7:4->0x2(TXD2) |
| 2)对内设置(uart) ULCON2: 0x13820000 0x3 UCON2: 0x13820004 1:0->01(polling) 3:2->01(polling) UTRSTAT2: 0->1(ready read) 1->1(发送完成) UBRDIV2:0x13820028 53 UFRACVAL2:0x1382002C 4 UTXH2: 0x13820020 发送buffer URXH2: 0x13820024 接收buffer |

3.编程

uart.c

cpp 复制代码
    		#define GPA1CON (*((volatile unsigned int *)0x11400020))
    		#define ULCON2 (*((volatile unsigned int *)0x13820000))
    		#define UCON2 (*((volatile unsigned int *)0x13820004))
    		#define UTRSTAT2 (*((volatile unsigned int *)0x13820010))
    		#define UBRDIV2 (*((volatile unsigned int *)0x13820028))
    		#define UFRACVAL2 (*((volatile unsigned int *)0x1382002C))
    		#define UTXH2 (*((volatile unsigned int *)0x13820020))
    		#define URXH2 (*((volatile unsigned int *)0x13820024))
    		
    		void uart_init(void) //初始化
    		{
    			//1.对外设置 (GPIO)
				GPA1CON &= ~0xff;  
				GPA1CON |= 0x22; //3:0->0x2(RXD2)  7:4->0x2(TXD2)	
            	//2.对内设置(uart)
                ULCON2 =  0x3;//8 1 无
                UCON2 &= ~0xf; 
                UCON2 |= 0x5; // 1:0->01(polling)  3:2->01(polling)
                UBRDIV2 = 53;
                UFRACVAL2 = 4;//波特率:115200
    		}
    		
    		void putc(char ch)
    		{
    			UTXH2 = ch;//发送数据
    			while((UTRSTAT2 & 0x2) == 0);//等待发送完成
    		}
    		
    		void puts(char *str)//一个一个发
    		{
    			while(*str)
    			{
    				putc(*str);
    				str++;
    			}
    		}
    		
    		char getc(void)
    		{
  				char ch;
    			while((UTRSTAT2 & 0x1) == 0);//等待接收缓冲区有数据
    			ch = URXH2;//接收数据
    		}
         void put_int(int num)
         {
             char buf[100];
             int i = 0;
             if (0 == num)
                 buf[i++] = '0';
             while (num) {
                 buf[i] = num % 10 + '0';
                 i++;
                 num = num / 10;
             }
             int j, k;
             for (j=0,k=i-1; j < k; j++,k--) {
                 char c = buf[j];
                 buf[j] = buf[k];
                 buf[k] = c;
             }
             buf[i] = '\r';
             buf[i+1] = '\n';
             buf[i+2] = '\0';
             puts(buf);
         }

main.c

cpp 复制代码
    			void mydelay(int x)
    			{
    				int i = 0;
    				while(x--)
    					for(i=1000;i>0;i--);
    			
    			}
    			int main()
    			{
    				uart_init(); //初始化
    				while(1)
    				{
    					puts("hello\r\n");
    					mydelay(500);
    				}
    			
    				return 0;
    			}

练习:串口控制LED 输入0时灯亮 输入1时灯灭

二、PWM

1.看原理图

|-------------------|
| GPD0_0: XpwmTOUT0 |

2.看芯片手册

|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1)对外设置(GPIO) GPD0CON: 0x114000A0 3:0->0x2(TOUT0) |
| 2)对内设置 TCFG0: 0x139D0000 7:0->255 (第一次分频) TCFG1: 0x139D0004 3:0 -> 0100(16分频) TCON: 0x139D0008 0->1/0(启动/关闭定时器) 1->1 1->0(manual off) 2->1(inveter on) 3->1(自动重装载) TCNTB0: 0x139D000C 300(周期值) TCMPB0: 0x139D0010 150(比较值) |

3.编程

pwm.c

cpp 复制代码
#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()
{
	//1.对外设置(GPIO)
	GPD0CON &= ~0xf;
	GPD0CON |= 0x2;//3:0->0x2(TOUT0)
	
	//2.对内设置
	TCFG0 &= ~0xff;
	TCFG0 |= 255; //第一次分频
	
	TCFG1 &= ~0xf;
	TCFG1 |= 0x4;//第二次分频

	TCNTB0 = 300;//周期值
	TCMPB0 = 150;//比较值
		
	TCON &= ~0xf;
	TCON |= 0xe;
	TCON &= ~0x2; // 0->0(关闭定时器) 1->1 1->0(manual off) 2->1(inveter on) 3->1(自动重装载)
}

void buzz_on()
{
	TCON |= 0x1; //0->1
}
void buzz_off()
{
	TCON &= ~0x1; // 0->0
}

三、看门狗定时器

0.作用

看门狗的作用就是防止程序发生死循环,或者说程序跑飞。

在系统运行以后也就启动了看门狗的计数器,看门狗就开始自动计数,如果到了一定的时间还不去清看门狗,那么看门狗计数器就会溢出从而引起看门狗中断,造成系统复位。

1.看原理图

|-----|
| 不需要 |

2.看芯片手册

|----------------------------------------------------------------------------------------------------------------------|
| WTCNT:0x10060008 3000 周期值 WTCON: 0x10060000 0->1(reset enable) 4:3->11(128分频) 5->1(WDT enable) 15:8->255 (255分频) |

3.编程

wdt.c

cpp 复制代码
#define WTCNT (*((volatile unsigned int *)0x10060008))
#define WTCON (*((volatile unsigned int *)0x10060000))
void wdt_init()
{
	WTCNT = 3000;// 周期值 1s = 1/100MHZ/(255+1)/128 * 3000
	WTCON &= ~(0xff<<8);
	WTCON |= 255 << 8; //第一次分频 255分频
	WTCON |= 0x3 << 3;//第二次分频 128
	WTCON |= 0x1; //reset enable
	WTCON |= 0x1<<5; // WDT enable
}

四、ADC数模转换

1.看原理图

|----------|
| XadcAIN3 |

2.看芯片手册

|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| ADCCON: 0x126C0000 16->1(12bit的分辨率) 15(转换完成的标志位) 14->1(分频使能) 13:6->19(分频值: 132+1) 2->0(正常模式) 1->1() 0->1(ADC start) ADCDAT:0x126C000C 转换结果 ADCMUX:0x126C001C 3:0->0x3 |

3.编程

adc.c

cpp 复制代码
#define ADCCON (*((volatile unsigned int *)0x126C0000))
#define ADCDAT (*((volatile unsigned int *)0x126C000C))
#define ADCMUX (*((volatile unsigned int *)0x126C001C))
void adc_init(void)
{
	ADCCON |= 0x1 << 16;//12bit的分辨率  15(转换完成的标志位)  
	ADCCON |= 0x1 << 14; //分频使能
	ADCCON &= ~(0xff<<6);
	ADCCON |= 132 << 6;//分频值: 132+1
	ADCCON &= ~(0x1<<2); //正常模式
	ADCCON &= ~0x2; //转换完成再去读数据

	ADCMUX &= ~0x7;
	ADCMUX |= 0x3;//AIN3
}

int readData(void)
{
	int data = 0;//保存转换之后的数字量
	int voltage = 0;//保存转换之后的电压

	ADCCON |= 0x1;//ADC使能
	while(ADCCON & (0x1<<15) == 0);//等待转换完成
	data = ADCDAT & 0xfff;//转换的数字量
	voltage = (1800 * (data+1)) / 4096;//电压值

	return voltage;

}

Makefile

perl 复制代码
all:
	arm-none-linux-gnueabi-gcc -fno-builtin -nostdinc -c -o start.o start.s
	arm-none-linux-gnueabi-gcc -fno-builtin -nostdinc -c -o main.o main.c
	arm-none-linux-gnueabi-gcc -fno-builtin -nostdinc -c -o uart.o uart.c
	arm-none-linux-gnueabi-gcc -fno-builtin -nostdinc -c -o pwm.o pwm.c
	arm-none-linux-gnueabi-gcc -fno-builtin -nostdinc -c -o wdt.o wdt.c
	arm-none-linux-gnueabi-gcc -fno-builtin -nostdinc -c -o adc.o adc.c
	arm-none-linux-gnueabi-ld start.o main.o uart.o pwm.o wdt.o adc.o -Tmap.lds -o pwm.elf
	arm-none-linux-gnueabi-objcopy -O binary pwm.elf pwm.bin
	arm-none-linux-gnueabi-objdump -D pwm.elf > pwm.dis
clean:
	rm -rf *.bak *.o *.elf *.dis *.bin

五、中断编程

|------------------------------------------------------------------------------------------------------------------------------|
| 1.理解 外部设备触发的一种异常; |
| 2.好处 能够让cpu及时响应外部设备的请求,即马上请求马上响应,提升的硬件的性能。 |
| 3.处理过程 1)当多个中断同时发生时,CPU如何处理? 优先级 2)当cpu正在处理中断是,突然又来一个同级或低优先级的中断时,cpu如何处理? cpu一定先处理完当前的中断,再去处理新中断; 3)中断标志位 中断处理完之后一定要清除中断标志位。 |

六、按键中断编程(按一下K2 执行打印,需要用到串口)

1.看原理图

|-----------------------------|
| GPX1_1: EINT9 port:25 Id:57 |

2.看芯片手册

|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1)对外设置(GPIO) GPX1CON: 0x11000C20 7:4->0xF //EXT_INT41 EXT_INT41CON: 0x11000E04 6:4->0x2 //下降沿触发 EXT_INT41_MASK: 0x11000F04 1->0 //Enables Interrupt EXT_INT41_PEND: 0x11000F44 1->1 //清除GPIO中断标志位 |
| 2)对内设置(INT) ICDISER_CPU: 0x10490104 25->1 //总使能 ICDIPTR14:0x10490838 0x01010101 //分发器 ICDDCR: 0x10490000 0->1 //分发使能 ICCICR_CPU0:0x10480000 0->1 //接口使能 ICCPMR_CPU0:0x10480004 255 //优先级 ICCEOIR_CPU0: 0x10480010 9:0->写中断ID //结束中断 ICDICPR_CPU: 0x10490284 25->1 //清除GIC中断标志位 ICCIAR_CPU0: 0x1048000C 9:0->ID //获取中断ID |

3.编程

irq.c

cpp 复制代码
#include "uart.h"

#define GPX1CON 		(*(volatile unsigned int *)0x11000C20)
#define EXT_INT41CON 	(*(volatile unsigned int *)0x11000E04)
#define EXT_INT41_MASK 	(*(volatile unsigned int *)0x11000F04)
#define EXT_INT41_PEND 	(*(volatile unsigned int *)0x11000F44)    
#define ICDISER_CPU 	(*(volatile unsigned int *)0x10490104)
#define ICDIPTR14 		(*(volatile unsigned int *)0x10490838)
#define ICDDCR 			(*(volatile unsigned int *)0x10490000)
#define ICCICR_CPU0 	(*(volatile unsigned int *)0x10480000) 
#define ICCPMR_CPU0 	(*(volatile unsigned int *)0x10480004)
#define ICCEOIR_CPU0 	(*(volatile unsigned int *)0x10480010)
#define ICDICPR_CPU 	(*(volatile unsigned int *)0x10490284)
#define ICCIAR_CPU0 	(*(volatile unsigned int *)0x1048000C)

void irq_init(void)
{
	//1.对外设置(GPIO)
	GPX1CON |= 0xF << 4; //EXT_INT41
	EXT_INT41CON &= ~(0x7<<4);
	EXT_INT41CON |= 0x2<<4;//下降沿触发
	EXT_INT41_MASK &= ~(0x1<<1); //Enables Interrupt

	//2.对内设置(INT)
	ICDISER_CPU |= 0x1 << 25; //总使能 
	ICDIPTR14 = 0x01010101; //分发器
	ICDDCR |= 0x1; //分发使能
	ICCICR_CPU0 |= 0x1; //接口使能
	ICCPMR_CPU0 = 255; //优先级
}

void do_irq(void)//自定义中断处理函数
{
	//1.判断是哪个irq
	int id = ICCIAR_CPU0 & 0x3ff; //获取中断ID
	switch(id)
	{
		case 57:
			putc('i');//处理中断
			EXT_INT41_PEND |= 0x1<<1; //清除GPIO中断标志位
			ICDICPR_CPU |= 0x1<<25;  //清除GIC中断标志位
			break;
		case 58:
				break;
		default:
				break;
		}
		ICCEOIR_CPU0 &= ~0x3ff; 
		ICCEOIR_CPU0 |= id; //结束中断
}

start.s

cpp 复制代码
       .text
       		b reset	@0x00 reset 
       		ldr pc,_undef_handler		@0x04 undefine
       		ldr pc, _swi_handler @0x08 swi  pc =* _swi_handle
       		ldr pc, _prefetch_abort_handler @0x0C prefetch abort
       		ldr pc, _data_abort_handler @0x10 data abort
       		nop @保留
       		ldr pc, _irq_handler @irq 0x18
       		ldr pc, _fiq_handler @fiq 0x1c
       	_swi_handler:
			.word swi_handler
        _irq_handler:
			.word irq_handler
         _fiq_handler:
			.word _fiq_handler
       
       swi_handler:
			stmfd sp!,{r0-r12,lr}  @现场保护
            @处理
            ldmfd sp!,{r0-r12,pc}^ @cpsr=spsr
                
                
       irq_handler:
			stmfd sp!,{r0-r12,lr}  @现场保护
            @处理
            ldmfd sp!,{r0-r12,pc}^ @cpsr=spsr	
       
        reset: @reset异常的处理函数
           mov r0,#0x3
           mov r1,r0
       
       .end

main.c

cpp 复制代码
void mydelay(int x)
{
	int i = 0;
	while(x--)
		for(i=1000;i>0;i--);
}

int main()
{
	irq_init();//irq初始化
	uart_init(); //初始化

	while(1)
	{
		putc('a');
		mydelay(500);
	}

	return 0;
}
相关推荐
森G9 小时前
七、04ledc-sdk--------makefile有变化
linux·c语言·arm开发·c++·ubuntu
VekiSon12 小时前
Linux内核驱动——杂项设备驱动与内核模块编译
linux·c语言·arm开发·嵌入式硬件
AI+程序员在路上13 小时前
Nand Flash与EMMC区别及ARM开发板中的应用对比
arm开发
17(无规则自律)19 小时前
深入浅出 Linux 内核模块,写一个内核版的 Hello World
linux·arm开发·嵌入式硬件
梁洪飞1 天前
内核的schedule和SMP多核处理器启动协议
linux·arm开发·嵌入式硬件·arm
代码游侠2 天前
学习笔记——Linux字符设备驱动
linux·运维·arm开发·嵌入式硬件·学习·架构
syseptember2 天前
Linux网络基础
linux·网络·arm开发
代码游侠2 天前
学习笔记——Linux字符设备驱动开发
linux·arm开发·驱动开发·单片机·嵌入式硬件·学习·算法
程序猿阿伟3 天前
《Apple Silicon与Windows on ARM:引擎原生构建与模拟层底层运作深度解析》
arm开发·windows
wkm9563 天前
在arm64 ubuntu系统安装Qt后编译时找不到Qt3DExtras头文件
开发语言·arm开发·qt