一 外部中断
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();
}
}
从中发现,寄存器的另一个作用,可以用来存储接受值和发送值。
此外,当把值赋给输出寄存器后,系统不断进入中断,发数据发送出去。直到发送完毕,才进行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; //超时计数器清零
}