(因对MSPM0研究不够深入,故暂不开启浏览权限,权当记录学习。但愿尽快掌握供大家免费阅读。有意者可私信我共同学习)
一、延时函数
1、官方延时函数
1.1 SysConfig配置
1.2 重定义延时函数
1.3 代码填写
int main(void)
{
SYSCFG_DL_init();
while (1) {
/*翻转PA0的输出*/
DL_GPIO_togglePins(GPIO_GRP_0_PORT,GPIO_GRP_0_LED_PIN);
delay_cycles(1600000);
}
}
2、自定义延时函数
void delay_ms(uint32_t ms)
{
while(ms--)
delay_cycles(CPUCLK_FREQ/1000);
}
二、GPIO口操作之点亮LED
1、命名、配置输出
2、配置上下拉,绑定引脚
或
快速绑定LED引脚
3.代码填写
实现效果:LED以一秒周期进行三色闪烁
while (1) {
DL_GPIO_setPins(GPIO_LED_PORT, GPIO_LED_PIN_BLUE_PIN);
delay_ms(500);
DL_GPIO_clearPins(GPIO_LED_PORT, GPIO_LED_PIN_BLUE_PIN);
delay_ms(500);
DL_GPIO_setPins(GPIO_LED_PORT, GPIO_LED_PIN_GREEN_PIN);
delay_ms(500);
DL_GPIO_clearPins(GPIO_LED_PORT, GPIO_LED_PIN_GREEN_PIN);
delay_ms(500);
DL_GPIO_setPins(GPIO_LED_PORT, GPIO_LED_PIN_RED_PIN);
delay_ms(500);
DL_GPIO_clearPins(GPIO_LED_PORT, GPIO_LED_PIN_RED_PIN);
delay_ms(500);
}
三、按键中断
1)配置名称、输出、上下拉、按键滤波
2)配置中断为下降沿
3) 代码填写
int main(void)
{
SYSCFG_DL_init();
NVIC_EnableIRQ(GPIO_KEY_INT_IRQN); //开启中断
while (1) {
}
}
void GROUP1_IRQHandler(void)
{
switch (DL_Interrupt_getPendingGroup(DL_INTERRUPT_GROUP_1)) {
case GPIO_KEY_INT_IIDX: //检测到中断翻转PA0电平
DL_GPIO_togglePins(GPIO_LED_PORT, GPIO_LED_PIN_BLUE_PIN); //翻转电平
break;
}
}
四、Timer定时器
1、定时器中断
1)Timer命名及分频
2)设置定时器周期及中断配置
3)代码填写
int main(void)
{
SYSCFG_DL_init();
/*使能定时器中断*/
NVIC_EnableIRQ(TIMER_0_INST_INT_IRQN);
/*使能定时器计数*/
DL_TimerA_startCounter(TIMER_0_INST);
while (1) {
// DL_GPIO_togglePins(GPIO_LED_PORT,GPIO_LED_PIN_BLUE_PIN);
// delay_ms(500);
}
}
/*定时器中断服务函数*/
void TIMER_0_INST_IRQHandler(void)
{
switch (DL_TimerA_getPendingInterrupt(TIMER_0_INST)) {
case DL_TIMERA_IIDX_ZERO:
/*定时器计数完成进入中断翻转LED灯的电平*/
DL_GPIO_togglePins(GPIO_LED_PORT,GPIO_LED_PIN_BLUE_PIN);
break;
default:
break;
}
}
2、定时器生成PWM波
1)定时器初始化配置
2)填写ARR,CCR及占空比数值
3)改变频率、占空比封装函数
/*
函数功能:Set_Duty()设定指定定时器指定通道的占空比
参数:
PWMA: 指定定时器名称 PWM_0_INST
Channel: 指定定时器通道 DL_TIMER_CC_0_INDEX / DL_TIMER_CC_1_INDEX
ARR: 定时器重装载值
duty: 设定占空比 归一化的占空比(0 ~ 1)
*/
void Set_Duty(GPTIMER_Regs * PWMA, DL_TIMER_CC_INDEX Channel, int ARR, float duty)
{
uint32_t CompareValue;
CompareValue = ARR - ARR * duty;
DL_Timer_setCaptureCompareValue(PWMA, CompareValue, Channel);
}
/*
函数功能:Set_Freq()设定指定定时器频率
参数:
PWMA: 指定定时器名称 PWM_0_INST
CLK_FREQ: 定时器总线频率 PWM_0_INST_CLK_FREQ
freq: 设定频率值
*/
void Set_Freq(GPTIMER_Regs *PWMA , uint32_t CLK_FREQ, uint32_t freq)
{
uint32_t period;
period = CLK_FREQ / freq;
DL_Timer_setLoadValue(PWMA, period);
}
4)main.c调用
int main(void)
{
SYSCFG_DL_init();
DL_Timer_startCounter(PWM_0_INST); //开启PWM波
Set_Freq(PWM_0_INST,PWM_0_INST_CLK_FREQ,5000); //改变频率为 5000Hz
Set_Duty(PWM_0_INST,DL_TIMER_CC_0_INDEX,3200,0.5); //设置PWM0的通道0的占空比为50%
while (1) {
}
}
六、DAC
1、DAC输出直流电压
1)使能DAC时钟
2) 配置DAC输出电压![](https://i-blog.csdnimg.cn/direct/f5fd2e8cd3b849a29bd07bef6143de25.png)
3)输入输出配置
4)代码填写
int main(void)
{
SYSCFG_DL_init();
DL_DAC12_output12(DAC0, 3000); //输出电压值 = 3000 / 4096 *3.3 V
DL_DAC12_enable(DAC0);
while (1) {
}
}
2、DAC+FIFO+TIMER输出指定波形
1)DAC触发时钟配置
2)相关配置
3)配置FIFO
4)配置中断、事件
5)代码填写
int i = 0;
uint32_t data[32] = {2048, 2447, 2831, 3185, 3496, 3750,
3940, 4056, 4095, 4056, 3940, 3750, 3496, 3185, 2831, 2447, 2048, 1648,
1264, 910, 599, 345, 155, 39, 0, 39, 155, 345, 599, 910, 1264, 1648};;
int main(void)
{
SYSCFG_DL_init();
/* 使能计时器以触发DAC */
DL_Timer_startCounter(TIMER_0_INST);
/* 使能DAC中断以更新DAC输出 */
NVIC_EnableIRQ(DAC12_INT_IRQN);
/*
* 发送信号至DAC输出.
* 定时器的触发周期可以在Sysconfig中进行配置。
* 信号频率将会取决于 sample time generator 和 number of samples:
*/
while (1) {
}
}
/*
* DL_DAC12_IIDX_FIFO_1_2_EMPTY即为我们选择的FIFO半满中断。
*/
void DAC12_IRQHandler(void)
{
switch (DL_DAC12_getPendingInterrupt(DAC0)) {
case DL_DAC12_IIDX_FIFO_1_2_EMPTY:
i = (i>32)?0:i+1;
DL_DAC12_output12(DAC0, data[i]);
break;
default:
break;
}
}
3、DAC+FIFO+DMA输出指定波形
1)初始化配置
2)DMA配置
3)中断、FIFO配置
4)代码填写
/* 正弦波样本数据 */
const uint16_t gOutputSignalSine64[] = {2048, 2248, 2447, 2642, 2831, 3013,
3185, 3347, 3496, 3631, 3750, 3854, 3940, 4007, 4056, 4086, 4095, 4086,
4056, 4007, 3940, 3854, 3750, 3631, 3496, 3347, 3185, 3013, 2831, 2642,
2447, 2248, 2048, 1847, 1648, 1453, 1264, 1082, 910, 748, 599, 464, 345,
241, 155, 88, 39, 9, 0, 9, 39, 88, 155, 241, 345, 464, 599, 748, 910, 1082,
1264, 1453, 1648, 1847};
int main(void)
{
SYSCFG_DL_init();
/* 设置DMA的源地址,目标地址,传输大小 */
DL_DMA_setSrcAddr(DMA, DMA_CH0_CHAN_ID, (uint32_t) &gOutputSignalSine64[0]); //这里源地址是正弦
DL_DMA_setDestAddr(DMA, DMA_CH0_CHAN_ID, (uint32_t) & (DAC0->DATA0)); //这里目标地址是DAC的DAT
DL_DMA_setTransferSize(DMA, DMA_CH0_CHAN_ID, sizeof(gOutputSignalSine64) / sizeof(uint16_t));
/* 使能DMA通道 */
DL_DMA_enableChannel(DMA, DMA_CH0_CHAN_ID);
while (1) {
}
}
七、ADC
1、单通道ADC单次中断配置
1)配置读取模式、触发模式
2)配置存储区域、绑定引脚
3)配置采样周期、开启中断
4)填写代码
volatile bool ADC_Flag; //ADC读取标志位
volatile uint16_t ADC_Val; //ADC读取数值
int main(void)
{
SYSCFG_DL_init();
NVIC_EnableIRQ(ADC12_0_INST_INT_IRQN); //启动中断
while (1) {
ADC_Flag = false;
DL_ADC12_startConversion(ADC12_0_INST); //启动转换
while(ADC_Flag == false); //等待转换
ADC_Val = DL_ADC12_getMemResult(ADC12_0_INST,DL_ADC12_MEM_IDX_0); //读取数值
DL_ADC12_enableConversions(ADC12_0_INST); //重新开启中断
}
}
void ADC12_0_INST_IRQHandler(void)
{
switch (DL_ADC12_getPendingInterrupt(ADC12_0_INST)) { //中断接收函数
case DL_ADC12_IIDX_MEM0_RESULT_LOADED:
ADC_Flag = true;
break;
default:
break;
}
}
2、单通道ADC轮询读取配置
1)使能重复采样模式
2)设置周期及中断
3)代码填写
volatile bool ADC_Flag; //ADC读取标志位
volatile uint16_t ADC_Val; //ADC读取数值
int main(void)
{
SYSCFG_DL_init();
NVIC_EnableIRQ(ADC12_0_INST_INT_IRQN); //启动中断
DL_ADC12_enableConversions(ADC12_0_INST);
ADC_Flag = false;
DL_ADC12_startConversion(ADC12_0_INST); //启动转换
while (1) {
// while(ADC_Flag == false); //等待转换
}
}
void ADC12_0_INST_IRQHandler(void)
{
switch (DL_ADC12_getPendingInterrupt(ADC12_0_INST)) { //中断接收函数
case DL_ADC12_IIDX_MEM0_RESULT_LOADED:
ADC_Val = DL_ADC12_getMemResult(ADC12_0_INST,DL_ADC12_MEM_IDX_0); //读取数值
ADC_Flag = true;
break;
default:
break;
}
}
3、单通道ADC+DMA传输
1)初始化配置
2)中断配置
3)DMA配置
4)代码填写
#define ADC_SAMPLE_SIZE (1024)
uint16_t ADC_Val[ADC_SAMPLE_SIZE];
volatile bool ADC_Flag;
int main(void)
{
SYSCFG_DL_init();
DL_DMA_setSrcAddr(DMA, DMA_CH0_CHAN_ID,(uint32_t)&(ADC0->ULLMEM.MEMRES[0])); //设置DMA源地址
DL_DMA_setDestAddr(DMA, DMA_CH0_CHAN_ID, (uint32_t)&ADC_Val[0]); //设置DMA目标地址
DL_DMA_setTransferSize(DMA, DMA_CH0_CHAN_ID, ADC_SAMPLE_SIZE); //设置DMA传输长度
DL_DMA_enableChannel(DMA, DMA_CH0_CHAN_ID); //使能DMA通道
/* Setup interrupts on device */
NVIC_EnableIRQ(ADC12_0_INST_INT_IRQN); //使能ADC中断
DL_ADC12_enableDMA(ADC12_0_INST); //使能ADC的DMA传输
DL_ADC12_startConversion(ADC12_0_INST); //开启ADC传输
ADC_Flag = false;
while (1) {
// while (false == ADC_Flag);
// ADC_Flag = false;//标志位清零
}
}
/*
* 中断的意义在于能够使程序在DMA数据传输完成之后
* 才开始下一次数据接收,能够使DMA传输更加稳定
*/
void ADC12_0_INST_IRQHandler(void)
{
switch (DL_ADC12_getPendingInterrupt(ADC12_0_INST)) {
case DL_ADC12_IIDX_DMA_DONE:
ADC_Flag = true;
break;
default:
break;
}
}
4、多通道ADC配置
1)
2)
3)
4)代码填写
volatile bool ADC_Flag;
volatile uint16_t ADC_Val0, ADC_Val1;
int main(void)
{
SYSCFG_DL_init();
NVIC_EnableIRQ(ADC12_0_INST_INT_IRQN); //开启第一个通道ADC中断
while (1) {
ADC_Flag = false;
DL_ADC12_startConversion(ADC12_0_INST);
while(ADC_Flag == false);
ADC_Val0 = DL_ADC12_getMemResult(ADC12_0_INST,DL_ADC12_MEM_IDX_0);
ADC_Val1 = DL_ADC12_getMemResult(ADC12_0_INST,DL_ADC12_MEM_IDX_1);
DL_ADC12_enableConversions(ADC12_0_INST);
}
}
void ADC12_0_INST_IRQHandler(void)
{
switch (DL_ADC12_getPendingInterrupt(ADC12_0_INST)) {
case DL_ADC12_IIDX_MEM1_RESULT_LOADED: //判断最后一路通道ADC中断
ADC_Flag = true;
break;
default:
break;
}
}
八、UART串口通信
1)串口速率配置
2)配置收发方式
3)开启接收中断
4)填写代码
uint8_t gEchoData;
int main(void)
{
SYSCFG_DL_init();
NVIC_ClearPendingIRQ(UART_0_INST_INT_IRQN); //清除标志位
NVIC_EnableIRQ(UART_0_INST_INT_IRQN); //启动串口接收中断
while (1) {
}
}
void UART_0_INST_IRQHandler(void)
{
gEchoData = DL_UART_Main_receiveData(UART_0_INST); //读取上位机发送数据
DL_UART_Main_transmitData(UART_0_INST,gEchoData); //传输数据
}
5)串口重定向
#include "stdio.h"
#include "string.h"
int fputc(int c, FILE* stream)
{
DL_UART_Main_transmitDataBlocking(UART_0_INST, c);
return c;
}
int fputs(const char* restrict s, FILE* restrict stream)
{
uint16_t i, len;
len = strlen(s);
for(i=0; i<len; i++)
DL_UART_Main_transmitDataBlocking(UART_0_INST, s[i]);
return len;
}
int puts(const char *_ptr)
{
int count = fputs(_ptr, stdout);
count += fputs("\n", stdout);
return count;
}
九、修改CPU主频
1)开启时钟树
2)改变倍频
十、OLED配置
1、软件模拟IIC
1)路径添加
2)引脚配置
3)代码填写
#include "oled.h"
#include "bmp.h"
int main( void )
{
SYSCFG_DL_init();
uint8_t t=' ';
OLED_Init(); //初始化OLED
while(1)
{
OLED_DrawBMP(0,0,128,64,BMP1);
delay_ms(500);
OLED_Clear();
OLED_ShowChinese(0,0,0,16);//中
OLED_ShowChinese(18,0,1,16);//景
OLED_ShowChinese(36,0,2,16);//园
OLED_ShowChinese(54,0,3,16);//电
OLED_ShowChinese(72,0,4,16);//子
OLED_ShowChinese(90,0,5,16);//科
OLED_ShowChinese(108,0,6,16);//技
OLED_ShowString(8,2,(uint8_t *)"ZHONGJINGYUAN",16);
OLED_ShowString(20,4,(uint8_t *)"2014/05/01",16);
OLED_ShowString(0,6,(uint8_t *)"ASCII:",16);
OLED_ShowString(63,6,(uint8_t *)"CODE:",16);
OLED_ShowChar(48,6,t,16);
t++;
if(t>'~')t=' ';
OLED_ShowNum(103,6,t,3,16);
delay_ms(500);
OLED_Clear();
}
}
2、硬件IIC
1)初始化配置
2)中断配置
十一、MPU6050
十二、编码器引脚中断四分频模式
1、配置引脚
2、中断配置
PIN_1配置同理
3、定时器配置
4、配置周期及中断
5、代码填写
volatile uint32_t EncoderA_Port, EncoderB_Port; //编码器端口
volatile int32_t EncoderA_CNT = 0, EncoderB_CNT = 0; //编码器计数值
volatile int32_t EncoderA_VEL = 0, EncoderB_VEL = 0; //马达速度
/*
* 编码器读取函数
* 编码器A、B分别对应编码器A、B的引脚
* EncoderA_CNT、EncoderB_CNT 分别对应编码器A、B的计数值
* EncoderA_Port、EncoderB_Port 分别对应编码器A、B的端口
*/
void Encodering(void)
{
EncoderA_Port = DL_GPIO_getEnabledInterruptStatus(GPIO_EncoderA_PORT, GPIO_EncoderA_PIN_0_PIN | GPIO_EncoderA_PIN_1_PIN);
EncoderB_Port = DL_GPIO_getEnabledInterruptStatus(GPIO_EncoderB_PORT, GPIO_EncoderB_PIN_2_PIN | GPIO_EncoderB_PIN_3_PIN);
/* 编码器A */
if((EncoderA_Port & GPIO_EncoderA_PIN_0_PIN) == GPIO_EncoderA_PIN_0_PIN) //编码器A-Pin0
{
if(!DL_GPIO_readPins(GPIO_EncoderA_PORT,GPIO_EncoderA_PIN_1_PIN)) EncoderA_CNT--;
else EncoderA_CNT++;
}
else if((EncoderA_Port & GPIO_EncoderA_PIN_1_PIN) == GPIO_EncoderA_PIN_1_PIN) //编码器A-Pin1
{
if(!DL_GPIO_readPins(GPIO_EncoderA_PORT,GPIO_EncoderA_PIN_0_PIN)) EncoderA_CNT++;
else EncoderA_CNT--;
}
DL_GPIO_clearInterruptStatus(GPIO_EncoderA_PORT, GPIO_EncoderA_PIN_0_PIN|GPIO_EncoderA_PIN_1_PIN);
/* 编码器B */
if((EncoderB_Port & GPIO_EncoderB_PIN_2_PIN) == GPIO_EncoderB_PIN_2_PIN)
{
if(!DL_GPIO_readPins(GPIO_EncoderB_PORT,GPIO_EncoderB_PIN_3_PIN)) EncoderB_CNT--;
else EncoderB_CNT++;
}
else if((EncoderB_Port & GPIO_EncoderB_PIN_3_PIN) == GPIO_EncoderB_PIN_3_PIN)
{
if(!DL_GPIO_readPins(GPIO_EncoderB_PORT,GPIO_EncoderB_PIN_2_PIN)) EncoderB_CNT++;
else EncoderB_CNT--;
}
DL_GPIO_clearInterruptStatus(GPIO_EncoderB_PORT, GPIO_EncoderB_PIN_2_PIN|GPIO_EncoderB_PIN_3_PIN);
}
/**************************************************************************
Function: Read encoder count per unit time
Input : TIMX:Timer
Output : none
函数功能:单位时间读取编码器计数
入口参数:TIMX:定时器
返回 值:速度值
**************************************************************************/
void Read_Encoder(void)
{
EncoderA_VEL = EncoderA_CNT;
EncoderA_CNT = 0;
EncoderB_VEL = EncoderB_CNT;
EncoderB_CNT = 0;
}
/*
* 编码器中断服务函数
*/
void GROUP1_IRQHandler(void)
{
/* 运行编码器 */
Encodering();
}
/*
* 编码器读取中断服务函数
* 读取编码器数值
*/
void TIMER_Encoder_Read_INST_IRQHandler(void)
{
switch (DL_TimerG_getPendingInterrupt(TIMER_Encoder_Read_INST)){
case DL_TIMER_IIDX_ZERO:
Read_Encoder(); //赋值编码器数值
break;
default:
break;
}
}