广州大学嵌入式第五次作业

目录

作业1:

1、编写UART_2串口发送程序时,初始化需要设置哪些参数?

2、假设速度为115200,系统时钟为72MHz,波特率寄存器BRR中的值应该是多少?

3、中断向量表在哪个文件中?表中有多少项?给出部分截图。

4、以下是中断源使能函数,假设中断源为TIM6,将函数实例化(写出各项具体数值)。

5、假设将UART_2和TIM6交换其在中断向量表中的位置和IRQ号, UART_2可以正常中断吗?

作业2:

        实现UART_2串口的接收程序,当收到字符时:

        ①在电脑的输出窗口显示下一个字符,如收到A显示B;

        ②亮灯:收到字符G,亮绿灯;收到字符R,亮红灯;收到字符B,亮蓝灯;收到其他字符,不亮灯。

实现方式:

1、用构件调用方式实现;

2、UART部分用直接地址方式实现(即不调用uart.c中的函数,其他部分如GPIO、中断设置可调用函数)。

源代码

作业1:

1、编写UART_2串口发送程序时,初始化需要设置哪些参数?

        需要设置UART_2 对应 GPIOx 的时钟以及波特率等参数。  

2、假设速度为115200,系统时钟为72MHz,波特率寄存器BRR中的值应该是多少?

        由ppt可算得:当"过采样"模式为1时:BRR的值为2*72000000/115200 = 1250;

                             当"过采样"模式为0时:BRR的值为72000000/115200 = 625;

3、中断向量表在哪个文件中?表中有多少项?给出部分截图。

        由图中可得,一共有99项。

4、以下是中断源使能函数,假设中断源为TIM6,将函数实例化(写出各项具体数值)。

由下图可得IRQn的值为54, 所以NVIC->ISER [54>>5] = (1 << 54%32);

5、假设将UART_2和TIM6交换其在中断向量表中的位置和IRQ号, UART_2可以正常中断吗?

  由下图可以看到初始时UART_2的IRQ号是38,TIM6的IRQ号是54。将他们的位置和IRQ号交换后,UART_2无法正常中断,因为交换后程序的中断请求和中断的处理程序不匹配。

作业2:

        实现UART_2串口的接收程序,当收到字符时:

        ①在电脑的输出窗口显示下一个字符,如收到A显示B;

        ②亮灯:收到字符G,亮绿灯;收到字符R,亮红灯;收到字符B,亮蓝灯;收到其他字符,不亮灯。

实现方式:

1、用构件调用方式实现;

实验结果:

       

       

2、UART部分用直接地址方式实现(即不调用uart.c中的函数,其他部分如GPIO、中断设置可调用函数)。

      

源代码

1、构件调用方式实现

main.c

#define GLOBLE_VAR
#include "includes.h"      //包含总头文件


//----------------------------------------------------------------------
//声明使用到的内部函数
//main.c使用的内部函数声明处

//----------------------------------------------------------------------
//主函数,一般情况下可以认为程序从此开始运行(实际上有启动过程,参见书稿)
int main(void)
 
{
 	uart_init(UART_2,115200);     //初始化串口模块   
 
	//关总中断
 
	DISABLE_INTERRUPTS;
 
	//初始化
 	gpio_init(LIGHT_GREEN,GPIO_OUTPUT,LIGHT_OFF);
    gpio_init(LIGHT_RED,GPIO_OUTPUT,LIGHT_OFF);
	gpio_init(LIGHT_BLUE,GPIO_OUTPUT,LIGHT_OFF);

	//打开使能模块中断
 
	uart_enable_re_int(UART_2);  //使能UART_USER模块接收中断功能
 
	//开总中断
	ENABLE_INTERRUPTS;

	//进入串口工具进行操作
  
	printf("-----------HYF选择工具选择串口工具-----------\n");
 
} 

isc.c

#include "includes.h"
//声明使用到的内部函数
//isr.c使用的内部函数声明处
void SecAdd1(uint8_t *p);

//=====================================================================
//函数名称:SYSTICK_USER_Handler(SysTick定时器中断处理程序)
//参数说明:无
//函数返回:无
//功能概要:(1)每10ms中断触发本程序一次;(2)达到一秒时,调用秒+1
//           程序,计算“时、分、秒”
//特别提示:(1)使用全局变量字节型数组gTime[3],分别存储“时、分、秒”
//          (2)注意其中静态变量的使用
//=====================================================================
void SysTick_Handler()
{
	//printf("***\n");
	static uint8_t SysTickCount = 0;
	SysTickCount++;    //Tick单元+1
	wdog_feed();      //看门狗“喂狗”
	if (SysTickCount >= 100)
	{
		SysTickCount = 0;
		SecAdd1(gTime);	
		printf("%d:%d:%d\n",gTime[0],gTime[1],gTime[2]);
	}
}

//===========================================================================
//函数名称:SecAdd1
//函数返回:无
//参数说明:*p:为指向一个时分秒数组p[3]
//功能概要:秒单元+1,并处理时分单元(00:00:00-23:59:59)
//===========================================================================
void SecAdd1(uint8_t *p)
{
	*(p+2)-=1;         //秒+1
	if(*(p+2)==0)     //秒溢出
	{
		if(*(p+1)==0)  //分溢出
		{
			//SysTick->CTRL = 0; 
			//SCB->ICSR |=(1<<25);
		}
		else{
			*(p+2)=60;       //清秒
			*(p+1)-=1;      //分-1
		}
	}	
 }

2、直接地址方式实现

main.c

#define GLOBLE_VAR
 
#include "includes.h"      //包含总头文件
 
int main(void)
 
{
 
    //定义uart寄存器相关地址
 
    volatile uint32_t* RCC_AHB2;     //GPIO的A口时钟使能寄存器地址
 
    volatile uint32_t* RCC_APB1;     //UART的2口时钟使能寄存器地址
 
    volatile uint32_t* gpio_ptr;       //GPIO的A口基地址
 
    volatile uint32_t* uart_ptr;       //uart2端口的基地址
 
    volatile uint32_t* gpio_mode;    //引脚模式寄存器地址=口基地址
 
    volatile uint32_t* gpio_afrl;      //GPIO复用功能低位寄存器
 
    volatile uint32_t* uart_brr;      //UART波特率寄存器地址
 
    volatile uint32_t* uart_isr;      // UART中断和状态寄存器基地址
 
    volatile uint32_t* uart_cr1;      //UART控制寄存器1基地址
 
    volatile uint32_t* uart_cr2;      // UART控制寄存器2基地址
 
    volatile uint32_t* uart_cr3;      // UART控制寄存器3基地址
 
    volatile uint32_t* uart_tdr;      // UART发送数据寄存器
 
    uint16_t usartdiv;   //BRR寄存器应赋的值
 
    
 
    //变量赋值
 
    RCC_APB1=0x40021058UL;    //UART时钟使能寄存器地址
 
    RCC_AHB2=0x4002104CUL;    //GPIO的A口时钟使能寄存器地址
 
    gpio_ptr=0x48000000UL;    //GPIOA端口的基地址
 
    uart_ptr=0x40004400UL;   //UART2端口的基地址
 
    gpio_mode=0x48000000UL;         //引脚模式寄存器地址=口基地址
 
    gpio_afrl=0x48000020UL;         //GPIO复用功能低位寄存器
 
    uart_cr1=0x40004400UL;          //UART控制寄存器1基地址
 
    uart_brr=0x4000440CUL;          //UART波特率寄存器地址
 
    uart_isr=0x4000441CUL;          //UART中断和状态寄存器基地址
 
    uart_tdr=0x40004428UL;          //UART发送数据寄存器
 
    uart_cr2=0x40004404UL;      //UART控制寄存器2基地址
 
    uart_cr3=0x40004408UL;       //UART控制寄存器3基地址
 
    //关总中断
 
    DISABLE_INTERRUPTS;
 
    
 
    //用户外设模块初始化
 
    gpio_init(LIGHT_BLUE,GPIO_OUTPUT,LIGHT_OFF);
 
    gpio_init(LIGHT_RED,GPIO_OUTPUT,LIGHT_OFF);
 
    gpio_init(LIGHT_GREEN,GPIO_OUTPUT,LIGHT_OFF);
 
    
 
    //下面执行uart_init(UART_User,115200);的直接地址方式
 
    //使能GPIOA和UART2的时钟
 
    *RCC_APB1|=(0x1UL<<17U);       //UART2时钟使能
 
    *RCC_AHB2 |=(0x1UL<<0U);       //GPIOA时钟使能
 
    
 
    //将GPIO端口设置为复用功能
 
    //首先将D7、D6、D5、D4清零
 
    *gpio_mode &= ~((0x3UL<<4U)|(0x3UL<<6U));
 
    //然后将D7、D6、D5、D4设为1010,设置PTA2、PTA3为复用功能串行功能。
 
    *gpio_mode |=((0x2UL<<4U)|(0x2UL<<6U));
 
    
 
    //选择引脚的端口复用功能
 
    //首先将D15~D8清零
 
    *gpio_afrl &= ~((0xFUL<<8U)|(0xFUL<<12U));
 
    //然后将D15~D8设置为01110111,分别将PTA3、PTA2引脚设置为USART2_RX、USART2_TX
 
    *gpio_afrl=(((0x1UL<<8U)|(0x2UL<<8U)|(0x4UL<<8U))|((0x1UL<<12U)
 
    |(0x2UL<<12U)|(0x4UL<<12U)));         
 
    
 
    //暂时禁用UART功能,控制寄存器1的第0位对应的是UE—USART使能位。
 
    //此位清零后,USART预分频器和输出将立即停止,并丢弃所有当前操作。
 
    *uart_cr1 &= ~(0x1UL);
 
    
 
    //暂时关闭串口发送与接收功能,控制寄存器1的发送器使能位(D3)、接收器使能位(D2)
 
    *uart_cr1 &= ~((0x1UL<<3U)|(0x1UL<<2U));
 
    
 
    //一位起始位,八位数据位
 
    *uart_cr1 &= ~((0x1UL << 28U)|(0x1UL << 12U));
 
    
 
    //过采样因子为16
 
    *uart_cr1 &= ~(0x1UL << 15U);
 
    
 
    //配置波特率
 
    usartdiv = (uint16_t)((SystemCoreClock/115200));
 
    *uart_brr = usartdiv;
 
    
 
    //初始化控制寄存器和中断状态寄存器、清标志位
 
    //关中断
 
    *uart_isr = 0x0UL;    
 
    //将控制寄存器2的两个使能位清零。D14—LIN模式使能位、D11—时钟使能位
 
    *uart_cr2 &= ~((0x1UL<<14U)|(0x1UL<<11U));
 
    //将控制寄存器3的三个使能位清零。D5 (SCEN) —smartcard模式使能位、
 
    //D3 (HDSEL) —半双工选择位、D1 (IREN) —IrDA 模式使能位
 
    *uart_cr3 &= ~((0x1UL<<5U) | (0x1UL<<3U) |(0x1UL<<1U));
 
    
 
    //启动串口发送与接收功能
 
    *uart_cr1 |= ((0x1UL<<3U)|(0x1UL<<2U));
 
    
 
    //开启UART功能
 
    *uart_cr1 |= (0x1UL<<0U);
 
    
 
    
 
    //完成直接地址方式实现使能模块中断
 
    //uart_enable_re_int(UART_User);  //使能UART_User模块接收中断功能
 
    //两部分,开放UART接收中断,开中断控制器IRQ中断
 
    //开放UART接收中断(将RXNEIE置为1)
 
    *uart_cr1 |= (0x1UL<<5);
 
    //开中断控制器IRQ中断,这里不属于uart部分,直接调用函数
 
    NVIC_EnableIRQ(USART2_IRQn);
 
    
 
    //开总中断
 
    ENABLE_INTERRUPTS;
 
 
    //提示进入串口工具进行操作
 printf("HYF“工具”→“串口工具”,打开接收User串口数据观察\r\n");
}

isc.c

include "includes.h"
 
#define GLOBLE_VAR
 
volatile uint32_t* uart_isr = (volatile uint32_t*)0x4000441CUL; // UART中断和状态寄存器基地址
 
volatile uint32_t* uart_rdr = (volatile uint32_t*)0x40004424UL; // UART接受数据寄存器
 
volatile uint32_t* uart_tdr = (volatile uint32_t*)0x40004428UL; // UART发送数据寄存器
 
void User_SysFun(uint8_t ch);
 
//======================================================================
 
//程序名称:UART_User_Handler
 
//触发条件:UART_User串口收到一个字节触发
 
//备    注:进入本程序后,可使用uart_get_re_int函数可再进行中断标志判断
 
//          (1-有UART接收中断,0-没有UART接收中断)
 
//======================================================================
 
void USART2_IRQHandler(void)
 
{
 
uint8_t ch;
 
uint8_t flag;
 
uint32_t num1;
 
uint32_t num2;
 
 
 
DISABLE_INTERRUPTS;   //关总中断
 

 
for(num1 = 0; num1 < 0xFBBB; num1++)//一直查询缓冲区是否有数据
 
{
 
//先判断isr状态位,再获取数据
 
if((*uart_isr)&(1<<5U))//第五位为1
 
{
 
ch = *uart_rdr;//从RDR寄存器取数
 
flag = 1;
 
*uart_isr &= ~(1<<5U);//第五位清零
 
break;
 
}
 
}
 
if(num1>=0xFBBB)//超过指定次数
 
{
 
ch = 0XFF;
 
flag = 0;
 
}
 
 
 
if(flag)                       //有数据
 
{
 
if((ch!='G')&&(ch!='R')&&(ch!='B'))
 
{
 
for (num2 = 0; num2 < 0xFBBB; num1++)//查询指定次数
 
{
 
//发送缓冲区为空则发送数据
 
//先判断isr状态位,再获取数据
 
if ((*uart_isr)&(1<<7U)) //检查第7位是否为一
 
{
 
*uart_tdr = (ch+1); //放到发送寄存器
 
break;
 
}
 
}
 
if (num2 >= 0xFBBB)
 
return 0; //发送超时,发送失败
 
gpio_set(LIGHT_RED,LIGHT_OFF);
 
gpio_set(LIGHT_BLUE,LIGHT_OFF);
 
gpio_set(LIGHT_GREEN,LIGHT_OFF);
 
}
 
if(ch == 'G')
 
{
 
uart_send_string(UART_User,(uint8_t *)"绿灯亮");
 
gpio_set(LIGHT_RED,LIGHT_OFF);
 
gpio_set(LIGHT_BLUE,LIGHT_OFF);
 
gpio_set(LIGHT_GREEN,LIGHT_ON);
uart_send1(UART_2,(ch+1)); 
}
 
if(ch == 'R')
 
{
 
uart_send_string(UART_User,(uint8_t *)"红灯亮");
 
gpio_set(LIGHT_GREEN,LIGHT_OFF);
 
gpio_set(LIGHT_BLUE,LIGHT_OFF);
 
gpio_set(LIGHT_RED,LIGHT_ON);
 uart_send1(UART_2,(ch+1));
}
 
if(ch == 'B')
 
{
 
uart_send_string(UART_User,(uint8_t *)"蓝灯亮");
 
gpio_set(LIGHT_GREEN,LIGHT_OFF);
 
gpio_set(LIGHT_RED,LIGHT_OFF);
 
gpio_set(LIGHT_BLUE,LIGHT_ON);
 uart_send1(UART_2,(ch+1));
}
 
}
 
ENABLE_INTERRUPTS;    //开总中断
 
 
 
 }
 
 
 
//内部函数
 
void User_SysFun(uint8_t ch)
 
{
 
    //(1)收到的一个字节参与组帧
 
    if(gcRecvLen == 0)  gcRecvLen =useremuart_frame(ch,(uint8_t*)gcRecvBuf);
 
    //(2)字节进入组帧后,判断gcRecvLen=0?若为0,表示组帧尚未完成,
 
    //     下次收到一个字节,再继续组帧
 
    if(gcRecvLen == 0) goto User_SysFun_Exit;
 
    //(3)至此,gcRecvLen≠0,表示组帧完成,gcRecvLen为帧的长度,校验序列号后(与
 
    //     根据Flash中倒数一扇区开始的16字节进行比较)
 
    //     gcRecvBuf[16]进行跳转
 
    if(strncmp((char *)(gcRecvBuf),(char *)((MCU_SECTOR_NUM-1)*MCU_SECTORSIZE+
 
       MCU_FLASH_ADDR_START),16) != 0)
 
    {
 
        gcRecvLen = 0;         //恢复接收状态
 
        goto User_SysFun_Exit;
 
    }
 
    //(4)至此,不仅收到完整帧,且序号比较也一致, 根据命令字节gcRecvBuf[16]进行跳转
 
    //若为User串口程序更新命令,则进行程序更新
 
    switch(gcRecvBuf[16])  //帧标识
 
    {
 
        case 0:
 
            SYSTEM_FUNCTION((uint8_t *)(gcRecvBuf+17));
 
            gcRecvLen = 0;         //恢复接收状态
 
        break;
 
        default:
 
        break;
 
    }
 
User_SysFun_Exit:
 
    return;
 
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值