ARM体系结构及接口技术-07ARM波形控制

串口通信设备

串口 UART 协议

在这里插入图片描述

uart 串口波形

发送 0xFF 0X00 0X04 0X08数据
串行通信参数设置:BAUD:115200,8位数据,1个停止位,无奇偶校验,发送顺序为低位先发送。
在这里插入图片描述
波形实现方法:

  1. CPU 已实现,仅需设置寄存器
  2. GPIO管脚模拟波形

示例

 //发送0x04 数据
void uart_tx(void)
{
	GPA1CON = GPA1CON&~(0xf<<4)|(0x01<<4);  //设置GPA1_1 GPIO输出模式
	
	//开始位
	GPA1DAT = GPA1DAT&~0x02 ;  //设置GPA1_1 低电平 
	delay10ms();  
	//传数据 0x04   0000 0100
	delay10ms();  //0
	delay10ms();  //0	 
	GPA1DAT = GPA1DAT|0x02 ; //1
	delay10ms();	
	GPA1DAT = GPA1DAT&~0x02 ;  //设置GPA1_1 低电平 
	delay10ms();  	//0
	delay10ms();  	//0	
	delay10ms();  	//0	
	delay10ms();  	//0
	//停止位
	GPA1DAT = GPA1DAT|0x02 ; //1
 	delay10ms();   		
}


void uart_rx(void)
{
	  unsigned char output=0;
		GPA1CON = GPA1CON&~(0xf);  //设置GPA1_1 GPIO输入模式
    //检测开始位
    while(1)
    {
    	 if(GPA1DAT&0x01==0)
    	 	break;
      delay10ms();
    }
    //接收数据
    if(GPA1DAT&0x01==0)  //bit0
    	 	 output=0;
    else
    	   output=1;	 
    if(GPA1DAT&0x01==0)  //bit1  	   
     	 	 output=output&~(0x01<<1);       	   
     else                	    	  
     	   output=output|(0x01<<1);	  

    if(GPA1DAT&0x01==0)  //bit2  	  
     	 	 output=output&~(0x01<<2);  
     else                	    	    
     	   output=output|(0x01<<2);	 
     	   ....
     	    	
	
}

I2C通信设备

I2C 协议

  • I2C总PHLIPS公司在八十年代初推出的一种串行的半双工总线,主要用于连接整体电路。
  • I2C总线为两线制,只有两根双向信号线。一根是数据线SDA,另一根是时钟线SCL。
  • 总线速度分为标准速度100kbps,快速模式400kbps,高速模式3.4Mbps
  • I2C硬件结构简单,接口连接方便,成本较低。因此在各个领域得到了广泛的应用。
  • I2C是具备多主机系统所需的包括总线裁决功能的高性能串行总线。
  • 每个接到I2C总线上的器件都有唯一的地址。主机与其它器件进行数据传送时总线上发送数据的器件为发送器,总线上接收数据的器件则为接收器。
    在这里插入图片描述

IIC总线的数据传送

  • IIC的通信过程
    主机发送起始信号启用总线
    主机发送一字节数据指明从机地址与下一字节传送方向
    对应的从机应答
    发送器发送一字节数据
    接收方应答
    … …
    数据传送完成后,主机发送停止信号释放总线使用权

  • 起始信号与终止信号
    SCL线为高电平期间,SDA线由高电平向低电平的变化表示起始信号
    SCL线为高电平期间,SDA线由低电平向高电平的变化表示终止信
    起始和终止信号都是由主机发出,起始信号产生后,总线就处于占用的态;终止信号产生后,总线就处于空闲态

在这里插入图片描述

  • 字节传送与应答
    每一个字节必须保证是8位长度。数据传送时,先传送最高位(MSB),每一个被传送的字节后面都必须跟随一位应答位(即一帧共有9位)
    在这里插入图片描述

  • I2C总线进行数据传送时,时钟信号为高电平期间,数据线上的数据必须保持稳定,只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化。
    在这里插入图片描述

IIC的寻址

  • I2C总线上传送的数据信号是广义的,既包括地址信号,又包括真正的数据信号
  • 主机在起始信号后必须传送一个从机的地址(7位),第8位是数据的传送方向位(R/T),用“0”表示主机发送数据(T),“1”表示主机接收数据(R)。总线上的每个从机都将这7位地址码与自己的地址进行比较,如果相同,则认为自己被主机寻址,根据R/T位将自己定为发送器或接收器
    在这里插入图片描述

常见的传送方式

  • 在总线的一传送过程中,可以有以下3种组合方式:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

I2C 波形

往ID为0x3c的I2C 设备写数据 0x2e 0x2e …

1.由主机发起,在SCL为高电平时,SDA由高到低切 变,形成开始信号;

2.接着是7位地址和一位读写标志,这里7位地址为0111100,即0x3c,正是我们代码中设置的地址ID;最后一位为0表示写操作;

3.接着在下一个时钟,主机以高电平状态释放SDA,这时从机响应,将SDA拉低了;

4.接着是两个8位数据00101110与响应,即0x2E,

5.还有其它数据和最后的停止位,图中被截掉了
在这里插入图片描述

PWM

PWM的概念

  • PWM(Pulse Width Modulation) :脉冲宽度调制
  • 占空比:就是输出的PWM中,高电平保持的时间与该PWM的时钟周期的时间之比
    在这里插入图片描述

PWM 蜂鸣器

在这里插入图片描述
在这里插入图片描述

PWM配置

step1:设置GPI/O为PWM模式

在这里插入图片描述
在这里插入图片描述

GPD0CON = (GPD0CON & ~(0xF << 0)) | (0x2 << 0);

step2:设置pwm频率

在这里插入图片描述
在这里插入图片描述

step2.1:第一级分频TCFG0

在这里插入图片描述

TCFG0 = (TCFG0 &~ (0xFF << 0)) | (100 << 0);
step2.2:第二级分频

在这里插入图片描述

TCFG1 = (TCFG1 &~ (0x0F << 0)) | (0x03<<0); 
step2.3:第三级分频

在这里插入图片描述

TCNTB0 = 200;           

step3:设置占空比

在这里插入图片描述

TCMPB0 = 100;    

在这里插入图片描述

step4:启动定时器

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

 TCON = (TCON & ~(0x0f << 0)) | (0x0A << 0);//先配置,先不启动
 TCON = (TCON & ~(0x0f << 0)) | (0x09 << 0);//配置好了再启动

示例

/*
   功能:实现K2 按下蜂鸣器发声,按下k3 蜂鸣器停止发声

*/

//----------------uart
#define GPA1CON 	(*(volatile unsigned int *)0x11400020) 	//volatile 确保本条指令不会因编译器的优化而省略
#define ULCON2 		(*(volatile unsigned int *)0x13820000) 	//串口2线控:数据位,停止位,奇偶校验位
#define UCON2 		(*(volatile unsigned int *)0x13820004) 	//串口2读取控制:串口读的方式(如:轮询/中断等),写的方式
#define UBRDIV2 	(*(volatile unsigned int *)0x13820028) 	//串口2波特率设置
#define UFRACVAL2 	(*(volatile unsigned int *)0x1382002c) 	//串口2波特率设置
#define UTXH2 		(*(volatile unsigned int *)0x13820020) 	//串口2发送缓存器
#define URXH2 		(*(volatile unsigned int *)0x13820024) 	//串口2接受缓存器
#define UTRSTAT2 	(*(volatile unsigned int *)0x13820010) 	//串口2状态寄存器

#define GPA0CON 	(*(volatile unsigned int *)0x11400000) 	//volatile 确保本条指令不会因编译器的优化而省略
#define ULCON0 		(*(volatile unsigned int *)0x13800000) 	//串口0线控:数据位,停止位,奇偶校验位
#define UCON0 		(*(volatile unsigned int *)0x13800004) 	//串口0读取控制:串口读的方式(如:轮询/中断等),写的方式
#define UBRDIV0 	(*(volatile unsigned int *)0x13800028) 	//串口0波特率设置
#define UFRACVAL0 	(*(volatile unsigned int *)0x1380002c) 	//串口0波特率设置
#define UTXH0 		(*(volatile unsigned int *)0x13800020) 	//串口0发送缓存器
#define URXH0 		(*(volatile unsigned int *)0x13800024) 	//串口0接受缓存器
#define UTRSTAT0 	(*(volatile unsigned int *)0x13800010) 	//串口0状态寄存器

#define ULCON3 		(*(volatile unsigned int *)0x13830000) 	//串口3线控:数据位,停止位,奇偶校验位
#define UCON3 		(*(volatile unsigned int *)0x13830004) 	//串口3读取控制:串口读的方式(如:轮询/中断等),写的方式
#define UBRDIV3 	(*(volatile unsigned int *)0x13830028) 	//串口3波特率设置
#define UFRACVAL3 	(*(volatile unsigned int *)0x1383002c) 	//串口3波特率设置
#define UTXH3 		(*(volatile unsigned int *)0x13830020) 	//串口3发送缓存器
#define URXH3 		(*(volatile unsigned int *)0x13830024) 	//串口3接受缓存器
#define UTRSTAT3 	(*(volatile unsigned int *)0x13830010) 	//串口3状态寄存器

//---------------interrupt_init
#define  GPX1CON        (*(volatile unsigned int *)0x11000c20)
#define  EXT_INT41CON   (*(volatile  int *)0x11000E04)
#define  EXT_INT41_MASK (*(volatile  int *)0x11000F04)
#define ICDISER1_CPU0   (*(volatile  int *)0x10490104)
#define ICDIPTR14_CPU0  (*(volatile  int *)0x10490838)
#define ICDDCR 			(*(volatile  int *)0x10490000)
#define ICCICR_CPU0  	(*(volatile  int *)0x10480000)
#define ICCPMR_CPU0  	(*(volatile  int *)0x10480004)
#define EXT_INT41_PEND 	(*(volatile  int *)0x11000f44)
#define ICCIAR_CPU0  	(*(volatile  int *)0x1048000C)
#define ICCEOIR_CPU0 	(*(volatile  int *)0x10480010)
#define ICDICPR1_CPU0 	(*(volatile  int *)0x10490284)

//-----------------led
#define  GPX2CON 		(*(volatile unsigned int *)0x11000C40) //
#define  GPF3CON        (*(volatile unsigned int *)0x11000C20) //
#define  GPX1DATA       (*(volatile unsigned int *)0x11000C24) //
#define  GPX2DATA       (*(volatile unsigned int *)0x11000C44) //
#define  GPF3DATA       (*(volatile unsigned int *)0x114001E4) //

#define GPX2_7_H  (GPX2DATA |= (0X01 << 7))  //LED2
#define GPX2_7_L  (GPX2DATA &= ~(0X01 << 7))

#define GPX1_0_H  (GPX1DATA |= (0X01 << 0)) //LED3
#define GPX1_0_L  (GPX1DATA &= ~(0X01 << 0))

#define GPF3_4_H  (GPF3DATA |= (0X01 << 4)) //LED4
#define GPF3_4_L  (GPF3DATA &= ~(0X01 << 4)

#define GPF3_5_H  (GPF3DATA |= (0X01 << 5)) //LED5
#define GPF3_5_L  (GPF3DATA &= ~(0X01 << 5))

//------------------pwm
#define GPD0CON     (*(volatile unsigned int *)0x114000a0)  //
#define TCFG0 		(*(volatile unsigned int *)0x139d0000)  //pwm第一级分频,设置Prescaler
#define TCFG1 		(*(volatile unsigned int *)0x139d0004)  //pwm第二级分频
#define TCNTB0 		(*(volatile unsigned int *)0x139d000c)  //pwm第三级分频
#define TCMPB0      (*(volatile unsigned int *)0x139d0010)  //设置占空比
#define TCON 		(*(volatile unsigned int *)0x139d0008)  //定时器启动设置(定时器开启,波形翻转,更新定时器初值,自动重装载)

#define BEEP_ON          1
#define BEEP_OFF         2

typedef enum
{
	DEVICE_UART_COM0 = 0,
	DEVICE_UART_COM1 = 1,
	DEVICE_UART_COM2 = 2,
	DEVICE_UART_COM3 = 3,
	DEVICE_BUTTON_KEY2,
	DEVICE_BUTTON_KEY3,
	DEVICE_PWM_BEEP,
	MAX_DEVICE
} DEVICE_LIST_E;



/*
   设置波特率为115200
//For example, if the Baud rate is 115200 bps and SCLK_UART is 100 MHz,UBRDIVn and UFRACVALn are:
//DIV_VAL = (SCLK_UART/(bps * 16)) - 1
//DIV_VAL = (100000000/(115200 * 16)) – 1
//= 54.253 – 1
//= 53.253
//UBRDIVn = 53 (integer part of DIV_VAL)
//UFRACVALn/16 = 0.253
//Therefore, UFRACVALn = 4
*/

void USART_Init(DEVICE_LIST_E Device_type)
{

	if (Device_type == DEVICE_UART_COM0)
	{
		//1.配置GPA0CON寄存器中的UART0
		//GPA0_0  UART_0_RXD
		//GPA0_1  UART_0_TXD
		GPA0CON &= 0xffffff00;
		GPA0CON |= 0x00000022;

		//2.配置ULCON0寄存器
		//串口0 8位数据位,1位停止位,无奇偶校验
		ULCON0 &= 0Xffffffc0;
		ULCON0 |= 0x00000003;

		//3.配置UCON0寄存器
		//通过轮询(polling)的模式读取串口数据     通过轮询(polling)的模式往串口写入数据数据
		UCON0 &= 0xfffffff0;
		UCON0 |= 0x00000005;
		//4.设置波特率为115200
		UBRDIV0 = 53;
		UFRACVAL0 = 4;
	}


	if (Device_type == DEVICE_UART_COM2)
	{
		GPA1CON &= 0xffffff00;
		GPA1CON |= 0x00000022;

		ULCON2 &= 0Xffffffc0;
		ULCON2 |= 0x00000003;

		UCON2 &= 0xfffffff0;
		UCON2 |= 0x00000005;

		UBRDIV2 = 53;
		UFRACVAL2 = 4;
	}

	if (Device_type == DEVICE_UART_COM3)
	{
		GPA1CON &= 0xff00ffff;
		GPA1CON |= 0x00220000;

		ULCON3 &= 0Xffffffc0;
		ULCON3 |= 0x00000003;

		UCON3 &= 0xfffffff0;
		UCON3 |= 0x00000005;

		UBRDIV3 = 53;
		UFRACVAL3 = 4;
	}


}

void putc(DEVICE_LIST_E Device_type, char c)
{

	switch (Device_type)
	{
	case DEVICE_UART_COM0:
		while (1)
		{
			if (UTRSTAT0 && 0X02)
				break;
		}
		UTXH0 = c;
		break;

	case DEVICE_UART_COM1:
		break;

	case DEVICE_UART_COM2:
		while (1)
		{
			if (UTRSTAT2 && 0X02)
				break;
		}
		UTXH2 = c;
		break;

	case DEVICE_UART_COM3:
		while (1)
		{
			if (UTRSTAT3 && 0X02)
				break;
		}
		break;

	default:
		break;
	}

}

char getc(void)
{
	while (1)
	{
		if (UTRSTAT0 && 0X01) break;
	}

	return URXH0;
}


void interrupt_init(DEVICE_LIST_E Device_type)
{
	//KEY2的初始化设置
	if (Device_type ==  DEVICE_BUTTON_KEY2)
	{
		//----- key2    GPX1_1    EINT9   SPIPORT:25 INTID:57
		//-----外: 配置管脚的工作模式

		//1-配置 GPX1_1为中断模式
		GPX1CON = (GPX1CON & ~(0x0F << 4)) | (0x0F << 4);
		//2-设置GPX1_1的触发方式为 下降沿触发
		EXT_INT41CON = (EXT_INT41CON & ~(0x7 << 4)) | (0x2 << 4);
		//3-GPX1_1 中断使能
		EXT_INT41_MASK = (EXT_INT41_MASK & ~(0X01 << 1)) | (0X00 << 1);

		//-----内: 功能块设置

		//4-EINT9 (GPX1_1)  GIC中断使能
		ICDISER1_CPU0 = ICDISER1_CPU0 | (1 << 25);
		//5-参考例子背景,用默认设置
		ICDIPTR14_CPU0 = 0x01010101;
		//6-GIC 分发总使能
		ICDDCR = ICDDCR | 1;
		//7-CPU0  中断使能
		ICCICR_CPU0 = 1;
		//8-设置CPU0的优先级门槛为最低
		ICCPMR_CPU0 = 0XFF;
	}

	//KEY3的初始化设置
	if (Device_type ==  DEVICE_BUTTON_KEY3)
	{
		//---- key3    GPX1_2    EINT10   SPIPORT:26 INTID:58
		-----外: 配置管脚的工作模式

		//1-配置 GPX1_2为中断模式
		GPX1CON = (GPX1CON & ~(0x0F << 8)) | (0x0F << 8);
		//2-设置GPX1_2的触发方式为 下降沿触发
		EXT_INT41CON = (EXT_INT41CON & ~(0x7 << 8)) | (0x2 << 8);
		//3-GPX1_2 中断使能
		EXT_INT41_MASK = (EXT_INT41_MASK & ~(0X01 << 2)) | (0X00 << 2);

		//-----内: 功能块设置

		//4-EINT10 (GPX1_2)  GIC中断使能
		ICDISER1_CPU0 = ICDISER1_CPU0 | (1 << 26);
		//5-参考例子背景,用默认设置
		ICDIPTR14_CPU0 = 0x01010101;
		//6-GIC 分发总使能
		ICDDCR = ICDDCR | 1;
		//7-CPU0  中断使能
		ICCICR_CPU0 = 1;
		//8-设置CPU0的优先级门槛为最低
		ICCPMR_CPU0 = 0XFF;


	}
}

void pwm_beep( int type)
{
	if(type == BEEP_ON)
	{
		TCON = (TCON & ~(0x01 << 0)) | (0x01 << 0);//启动定时器(启动定时器beep)
	}
	
	if(type == BEEP_OFF)
	{
		TCON = (TCON & ~(0x01 << 0)) | (0x00 << 0);//关闭定时器(beep)
	}
}

void do_irq(void )
{
	int irq_num;
	irq_num = ICCIAR_CPU0 & 0X3ff; //获取中断ID号

	switch (irq_num)
	{
	//KEY2
	case 57:
		putc(DEVICE_UART_COM0, 'K');
		putc(DEVICE_UART_COM0, '2');
		pwm_beep(BEEP_ON);
		
		EXT_INT41_PEND = EXT_INT41_PEND | (0X01 << 1); //清GPX1_1中断标志
		ICDICPR1_CPU0 = ICDICPR1_CPU0 | (0x01 << 25);  //清GCI中GPX1_1ç„中断标志
		break;

	//KEY3
	case 58:
		putc(DEVICE_UART_COM0, 'K');
		putc(DEVICE_UART_COM0, '3');
		pwm_beep(BEEP_OFF);
		EXT_INT41_PEND = EXT_INT41_PEND | (0X01 << 2); //清GPX1_2中断标志
		ICDICPR1_CPU0 = ICDICPR1_CPU0 | (0x01 << 26);  //清GCI中GPX1_2中断标志
		break;
	default:
		break;
	}

	ICCEOIR_CPU0 = (ICCEOIR_CPU0 & ~0x3ff) | irq_num;   //结束对应的中断

}

void led_init(void)
{
	GPX2CON = (GPX2CON & ~(0X0F << 28)) | (0X01 << 28); //设置LED2灯的配置寄存器 GPX2CON7为输出状态
	GPX1CON = (GPX1CON & ~(0X0F << 0)) | (0X01 << 0); 	//设置LED3灯的配置寄存器 GPX1CON0为输出状态
	GPF3CON = (GPF3CON & ~(0X0F << 16)) | (0X01 << 16); //设置LED4灯的配置寄存器 GPF3CON4为输出状态
	GPF3CON = (GPF3CON & ~(0X0F << 20)) | (0X01 << 20); //设置LED5灯的配置寄存器 GPF3CON5为输出状态

}


void pwm_init(DEVICE_LIST_E Device_type)
{
	if(Device_type == DEVICE_PWM_BEEP)
	{
		//----------外部   配置GPIO-----------------
		//1.设置GPD0_0为PWM模式
		GPD0CON = (GPD0CON & ~(0xF << 0)) | (0x2 << 0);
		
		//-------------内部配置PWM功能块------------
		//2.设置PWM周期为625Hz
		//  pwm_out = pclk/TCFG0/TCFG1/TCNTB0 = 100M/100/8/200 = 625HZ
		TCFG0 = (TCFG0 &~ (0xFF << 0)) | (100 << 0);//设置第一级分频值为100
		TCFG1 = (TCFG1 &~ (0x0F << 0)) | (0x03<<0); //设置第二级分频值为8
		TCNTB0 = 200;                              //设置第三级分频值为200

		//3.设置占空比为50%
		TCMPB0 = 100;          //设置占空比为 = TCMPB0/TCNTB0 = 100/200 = 1/2  ,输出的是方波

		//4.启动定时器
	   TCON = (TCON & ~(0x0f << 0)) | (0x0A << 0);//先配置,先不启动
	   TCON = (TCON & ~(0x0f << 0)) | (0x09 << 0);//配置好了再启动
	}
}

int main(void)
{
	USART_Init(DEVICE_UART_COM0);
	led_init();
	interrupt_init(DEVICE_BUTTON_KEY2);
	interrupt_init(DEVICE_BUTTON_KEY3);
	pwm_init(DEVICE_PWM_BEEP);
	char c;

	while (1)
	{

#if 0
		c = getc();
		delay1s();

		putc(vDevice, c);
		delay1s();
#endif

	}
	return 0;
}

参考

https://blog.youkuaiyun.com/m0_37542524/article/details/85947369

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值