外部中断和SysTick实验和uart串口实验

一 外部中断
1.main.c

#include "MyIncludes.h"

void GPIO_EXTI_ISR(uint16_t GPIO_Pin)
{
	if(GPIO_Pin == GPIO_PIN_11)
	{
		HAL_GPIO_TogglePin(GPIOI,GPIO_PIN_1);
	}
}

int main(void)
{
	System_Init();
	SysTick_Init(NULL);	
	LED_Init();		
	Exti_Init(GPIO_EXTI_ISR);	
	while(1)
	{
	}
}

2.Exti_Init(GPIO_EXTI_ISR);
把Pin11,GPIOI设置为外部中断输入。在中断被触发时,进入GPIO_EXTI_ISR()函数。

void Exti_Init(void (*ISR)(uint16_t GPIO_Pin))
{
	GPIO_InitTypeDef GPIO_InitStruct;
  
	Exti_ISR.exti_isr = ISR;
	__GPIOI_CLK_ENABLE(); //ʹÄÜGPIOIʱÖÓ
  
    //配置PI11为输入
    GPIO_InitStruct.Pin = GPIO_PIN_11;  
    GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;       //ÉÏÉýÑØ´¥·¢
    GPIO_InitStruct.Pull = GPIO_NOPULL;               //Íⲿµç·ÒÑÏÂÀ­  
    GPIO_InitStruct.Speed = GPIO_SPEED_FAST;          //50MHz 
    HAL_GPIO_Init(GPIOI, &GPIO_InitStruct);
    
    /* Enable and set Button EXTI Interrupt to the lowest priority */
    HAL_NVIC_SetPriority(EXTI15_10_IRQn , 0x0F, 0);
    HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);
}

二 SysTick
//SysTick调用。

#include "MyIncludes.h"

u16 sys_cnt = 0;
void systick_isr(void)
{
	if(sys_cnt < 1000) sys_cnt++;
	else
	{
		sys_cnt = 0;
		HAL_GPIO_TogglePin(GPIOI,GPIO_PIN_1);
	}
}

int main(void)
{
	System_Init();
	
	LED_Init();
	
	SysTick_Init(systick_isr);
	
	while(1)
	{

	}
}

//函数定义。

/*******************************************************************************
* Function Name  : SysTick_Handler
* Description    : SysTickÖжϷþÎñº¯Êý
* Input          : None
* Output         : None
* Return         : None
* Note			 : 1msÖжÏ
*******************************************************************************/
void SysTick_Handler (void)		
{           
	//Clear System Tick counter flag
	SysTick->CTRL &= ~SysTick_CTRL_COUNTFLAG_Msk;
	HAL_IncTick();
	if(SysTick_Info.Operation != NULL) SysTick_Info.Operation();
}

/*******************************************************************************
* Function Name  : SysTick_Init
* Description    : SysTick³õʼ»¯
* Input          : ISR: Öжϻص÷
* Output         : None
* Return         : None
* Note			 : None
*******************************************************************************/
void SysTick_Init(void (*ISR)(void))
{
	SysTick_Info.Operation = ISR;
	//Initialize System Tick with 1ms time interval	
	SysTick_Config(HAL_RCC_GetHCLKFreq()/1000);
}

这两个例程类似,都是定义一个中断服务函数。把函数名作为变量进行初始化设置。具体的定时时间,那个引脚被设置为外部中断输入,在init设置。
三 串口传输
主函数的内容
**int main(void)
{
System_Init();

LED_Init();	

SysTick_Init(systick_isr);
	
recv_timeout = 150;  //³õʼ»¯³¬Ê±Öµ
send_len = 20;

sprintf((char *)test_txbuf,"hello world!!!\r\n");
USART6_Init(9600,uart_tx,uart_rx);

while(1)
{	
	Uart_RecvProcess();
	
	Key_Read();
	
	if(Key_Info.Num_Last != Key_Info.Num)
	{
        Key_Info.Num_Last = Key_Info.Num;
		
		if(Key_Info.Num != 0)
		{
			switch(Key_Info.Num)
			{
				case KEY_ONE:       //·­×ªLED
					 printf("STM32F746 USART TEST!!!\r\n");
					 break;
				default: break;
			}
		}
	}
}

}
**

USART6_Init(9600,uart_tx,uart_rx);
这个函数特别熟悉。就是指在发生中断后,系统要执行的服务函数是什么?中断包括接受中断和发送中断。每进入一次发送中断,就把一个字节数据赋值给SEND_BUF6(USART Transmit Data register)。每进入一次接受中断,就把收到的1字节数据存到test_rxbuf。如何把接受的数据与test_rxbuf两者联系起来的呢?
接收到的数据保存到RECV_BUF6(Receive Data register)
RECV_BUF6如何把值传到RxData?
因为
Usart_ISR.U6RXOperation(RECV_BUF6),
又因为
Usart_ISR.U6RXOperation = RxFunction;
所以RECV_BUF6的这个寄存器的值被送到RxData中。

void systick_isr(void)
{
	if(sys_cnt < 100) sys_cnt++;
	else
	{
		sys_cnt = 0;
		HAL_GPIO_TogglePin(GPIOI,GPIO_PIN_1);
	}
	
	if(recv_timeout < 30) recv_timeout++;
	if(recv_timeout == 20) 
	{
		recv_complete = 1;
	}
}

这个函数就可以实现每隔20ms,recv_complete就变成1.

void Uart_RecvProcess(void)
{
	if(recv_complete == 1)    //
	{
		recv_complete = 0;
		recv_len = rx_index;
		rx_index = 0;
		//发出接受到的数据
		Uart_Fill_Tx(test_rxbuf,recv_len);
	}
}

Uart_Fill_Tx(test_rxbuf,recv_len);作用是把接收到的数据拷贝到发送区test_txbuf,并且清零。

**void uart_rx(unsigned char RxData)
{
	if(rx_index < RECV_LENGTH)
	{
		test_rxbuf[rx_index++] = RxData;	
	}
	recv_timeout = 0;      //超时计数器清零
}**

接受服务函数,如果当前接受数据长度不足100个,就保存到test_rxbuf,否则不保存。每接受一字节数据,就超时计数器清零。当数据接受完毕后,超时计数器溢出,自然就可以把所接受的数据复制到发送区,并且挨个发送出去。

void uart_tx(void)
{
	if(tx_index < send_len)
	{
		SEND_BUF6 = test_txbuf[tx_index++];
	}
	else
	{
		USART6_TX_ISR_DISABLE();
	}
}

从中发现,寄存器的另一个作用,可以用来存储接受值和发送值。
外部中断和SysTick实验和uart串口实验_第1张图片
此外,当把值赋给输出寄存器后,系统不断进入中断,发数据发送出去。直到发送完毕,才进行while{}里面语句的进行。

程序理解:

无论发出还是接受,都需要中断。
当发生接受中断,则把接受到的数值发送到接收函数。
当发生发出中断,则说明发送完成。

当接受到第一个数据时,即第一次进入 uart_rx函数时,recv_timeout = 0; 这样如果进入10次程序后,结束接受,那么就要加一个超时函数。

if(temp&UART_LSR_RDR)			//接收到数据
	{	  
 		if(Usart_ISR.U6RXOperation != NULL) Usart_ISR.U6RXOperation(RECV_BUF6); 		
	} 
	 	
	if(temp&UART_LSR_THRE)			//发送完成
	{	 
		USART6_SR &= ~UART_LSR_THRE;	  //清零发送标志
		if(Usart_ISR.U6TXOperation != NULL) Usart_ISR.U6TXOperation();				

每完成一次接受,就把这次接受的数值保存到test_txbuf中,知道把所有的数值都接受成功。当然接受数字个数是有限制的。最多sendlen个.如果多了,就不再接受了,关闭接受模块。
同理,每完成一次发送,就进入一次uart_tx()函数中,从而实现挨个发送数据功能。

void uart_tx(void)
{
	if(tx_index < send_len)
	{
		SEND_BUF6 = test_txbuf[tx_index++];
	}
	else
	{
		USART6_TX_ISR_DISABLE();
	}
}

u8 rx_index;
void uart_rx(unsigned char RxData)
{
	if(rx_index < RECV_LENGTH)
	{
		test_rxbuf[rx_index++] = RxData;	
	}
	recv_timeout = 0;      //超时计数器清零
}

你可能感兴趣的:(stm32f746ng,例程学习)