实验室的MCU项目中主要核心CPU使用的是Cortex M3 ,就此学习嵌入式工作组的头文件以及一些函数学习,作为自己嵌入式学习的入门,持之以恒,目标明年7月找工作之前能够比较熟悉的掌握了解嵌入式开发。
首先main.c一个简单的函数:
int main(void)
{
// BSP_LED_Init();
// delay_init();
// u8 flag = true;
// tim0_cnt = 0;
example_uart();
// tim_nvic_init(1); // 定时 1ms
while(1)
{
// OpenLED();
// delay_ms(1000);
// CloseLED();
// delay_ms(1000);
}
}
可以看到主函数main.c内只有一个example_uart的函数,这是一个uart中断的例程函数。
进入这个可以看见在头文件中声明了以下几组函数:
////////////////////////////////////////////////////////////////////////////////
#ifndef __BSP_UART_H
#define __BSP_UART_H
////////////////////////////////////////////////////////////////////////////////
#include “type.h”
// 定义最大接收字节数 200
#define UART_REC_LEN 200
////////////////////////////////////////////////////////////////////////////////
///
#ifdef BSP_UART_C
#define GLOBAL
#else
#define GLOBAL extern
#endif
// 接收状态标记
GLOBAL u16 UART_RX_STA;
// 接收缓冲,最大 UART_REC_LEN 个字节
GLOBAL u8 UART_RX_BUF[UART_REC_LEN];
GLOBAL char printBuf[100];
#undef GLOBAL
////////////////////////////////////////////////////////////////////////////////
void UartSendByte(u8 dat);
void UartSendGroup(u8* buf,u16 len);
void uart_nvic_init(u32 bound);
void example_uart();
进入example_uart ()函数体:
void example_uart()
{
u8 t, len;
u16 times = 0;
u8 tog;
delay_init();
BSP_LED_Init();
LED0_on();
LED0_off();
/*串口初始化为9600*/
uart_nvic_init(9600);
while(1)
{
if(UART_RX_STA & 0x8000)
{
/*得到此次接收到的数据长度*/
len = UART_RX_STA & 0x3fff;
UartSendGroup((u8*)printBuf, sprintf(printBuf,"\r\nYou Send MSG:\r\n"));
for(t = 0; t < len; t ++)
{
while (UART_GetFlagStatus(UART0, UART_FLAG_TXFEMP) == RESET);
UART_SendData(UART0, (u8)UART_RX_BUF[t]);
}
/*插入换行*/
UartSendGroup((u8*)printBuf, sprintf(printBuf,"\r\n\r\n"));
UART_RX_STA = 0;
}else
{
times++;
if(times % 500 == 0)
{
UartSendGroup((u8*)printBuf, sprintf(printBuf,"\r\n ULP32 FPGA COM TEST! 串口测试 \r\n"));
}
if(times % 200 == 0) UartSendGroup((u8*)printBuf, sprintf(printBuf,"Place Send Data and Enter!\r\n"));
/*闪烁LED,提示系统正在运行*/
if(times % 10 == 0)
{
if(tog == false)
{
LED0_on();
tog = true;
}
else
{
tog = false;
LED0_off();
}
}
delay_ms(5);
}
}
}
首先是delay_init()函数:
这是一个Systicks中断函数:
//配置systick中断时间
void delay_init(void)
{
//1 us定时中断
//SysTick_Config(SYSTEM_CLOCK / 1000000);
//1ms 定时中断
SysTick_Config(SYSTEM_CLOCK / 1000);//定时时间计算公式T=ticks*(1/f)=25_000*(1/25000000)=1ms
// SysTick_Config(SysTick_LOAD_RELOAD_Msk);
}
进入配置函数SysTick_Config函数:
__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)
{
if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk)//max SysTick_LOAD_RELOAD_Msk is 0xff_ffff, equal to 16_777_215\判断是否超出范围
{
return (1UL); /* Reload value impossible */
}
SysTick->LOAD = (uint32_t)(ticks - 1UL); /* set reload register /
NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); / set Priority for Systick Interrupt /
SysTick->VAL = 0UL; / Load the SysTick Counter Value /
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
SysTick_CTRL_TICKINT_Msk |
SysTick_CTRL_ENABLE_Msk; / Enable SysTick IRQ and SysTick Timer /
return (0UL); / Function successful */
}
这个函数里面包含了SysTick–>Load设置计数值
NVIC_SetPriority设置SysTick中断优先级
__STATIC_INLINE void __NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)
{
if ((int32_t)(IRQn) >= 0)
{
NVIC->IP[((uint32_t)IRQn)] = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL);
}
else
{
SCB->SHP[(((uint32_t)IRQn) & 0xFUL)-4UL] = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL);
//SCB用来处理内核中断,中断号小于0
}
}
这里IRQ为-1,priority=7;因为SysTick中断属于内核中断,中断号小于0;
计算SCB->SHP[11]=15
这里面寄存器很多,在这里大部分我们不用去管,有一个数组SHP[12],一定要看清他是8位数组啊!这个数组是很重要的,他是用来设置内核异常的优先级别,并不是想的在NVIC里设置,那个是大于15号中断的优先组别,换句话就是外部中断什么看门狗,定时器,串口啥的,外设的中断优先级设置在NVIC地IP数组中,而小于这个的都是内部异常,他不归NVIC管制,他受谁管呢?就是这个SHP[12],滴答属于内核的异常所以他要用SHP[12]来设置,和内核手册中讲到的那三个(SHRP1-SHRP3)32位寄存器一一对应,算下来正好有12个字节,最后一个字节就是我要的SYStick的优先级设置,他只用了他的高四位,而第四位保留,所以他的范围是0-15之间的任意数!!
SysTick-Val设置counter值
SysTick->CTRL Enable SysTick IRQ and SysTick Timer Function successful


Systick就是一个定时器而已,只是它放在了NVIC中,主要的目的是为了给操作系统提供一个硬件上的中断(号称滴答中断)。滴答中断?这里来简单地解释一下。操作系统进行运转的时候,也会有“心跳”。它会根据“心跳”的节拍来工作,把整个时间段分成很多小小的时间片,每个任务每次只能运行一个“时间片”的时间长度就得退出给别的任务运行,这样可以确保任何一个任务都不会霸占整个系统不放。或者把每个定时器周期的某个时间范围赐予特定的任务等,还有操作系统提供的各种定时功能,都与这个滴答定时器有关。因此,需要一个定时器来产生周期性的中断,而且最好还让用户程序不能随意访问它的寄存器,以维持操作系统“心跳”的节律。 只要不把它在SysTick控制及状态寄存器中的使能位清除,就永不停息。
作者:yx_l128125
来源:优快云
原文:https://blog.youkuaiyun.com/yx_l128125/article/details/7884423
版权声明:本文为博主原创文章,转载请附上博文链接!
至此SysTick中断设置完毕
下面设置串口初始化
更正:IER[0]先置位,当data_ready被置位后进入接收中断