看过的每部电影和番剧总有一些话会让自己印象深刻,或许下次摸鱼的时候会写一写以前的吧......?
不过写了就不算是摸鱼了
Everybody loves Somebody
说到这句话脑子里就不自觉地响起了蹩脚的日式英语,这就是被洗脑了?
每个人都有其所爱,看到有人这样翻译感觉真的有被暖到。作为纯爱战士我当然是冲着纯爱来了玉子市场,最后在玉子市场里面我也是真正的看到了纯爱,只不过是邻里之间的纯爱,纯纯的关爱。
兔山真的太好了,看到最后真的觉得整个人都被温馨包围着。虽然看的很迷糊但是还是看出了玉子幼年便丧失了母亲,还能这样乐观真的让人很惊讶,而且玉子真的是傻傻的,很可爱,对年糕有着奇怪的偏执但是并不影响这表现出她对生活的热爱。
玉子市场,是兔山,是围绕在玉子周围的市场。但是从头到尾真的没看到一点印象中市场该有的感觉,每次交易都是围绕着玉子、朋友进行的,目光所及之处满是慷慨的馈赠白嫖党狂喜。听说王子妃一事,大家都纷纷祝愿玉子幸福,又安慰豆大不要伤心,要失去一些东西才能得到新的东西(当然我是非常不希望玉子当上王子妃的)。
顺带一提,最终玉子拒绝当上王子妃的时候我真的狂喜!!
看得出玉子和饼藏的感情萌芽,不过玉子真的好迟钝,也好可爱。
感受得到豆大和雏子(原谅我其实没记住妈妈的名字)年轻的时候的感情,真的很让人羡慕哈!
又想起了馅子和悠月的可爱感情(小盆友互相喜欢什么的真的太可爱啦~)
单身狗流下了泪水
不写了不写了,越看自己写的东西越感觉:
写的真烂呀T_T
总之就是完结撒花!
摸鱼结束,该干活了orz
这里是后期的我自己,文章的正文是在学习过程中随着进度一点一点写出来的,现在作品完成的接近尾声了,但是我觉得自己的了解并不够多,先说说自己的感受吧。
首先最大的感受就是使用TI的SDK库函数的时候的陌生感。这里就不得不对比一下HAL库和SDK了:
首先HAL给人最直观的感受就是封装度高,更适合新手上手,上手起来也很快。但是这也同样是HAL库的缺点。
在使用HAL库的时候,让人真的觉得就是在“使用”。因为你不知道里面干了什么,怎么干的,HAL的封装在你的面前就是一个巨大的黑盒子,使用的时候他在刻意的引导着我们让我们只关心“能用就行”,却忽略了背后的一些机制和原理。这不是HAL的问题,HAL的初心就是让程序员能脱离在机械化的初始化中浪费的时间,但是有一个巨大的前提----这个程序员懂得其中的原理。而向我们这样的新手在用的时候就真的只会关心“能用就行”。
SDK则不一样,很多东西在不摸懂其中的原理之前是没办法调通的,这就逼迫着你去不断地翻阅参考手册、翻阅库函数手册、查资料等等,无形中增加了学习的深度以及对于原理的理解。
懂得不多,感受大概就这些,下面是正文。
系统时钟树以及滴答时钟
System Timer (SysTick)----系统滴答时钟
需要知道的内容:
- Systick内部含有一个24位计数器,计数器最大值为1<<24
- Systick计数频率等于系统主频(MCLK)
- Systick计数器的计数方式为递减计数
Systick共含有三个寄存器功能分别如下:
- SysTick Control and Status Register (STCSR): A control and status register to configure its clock,enable the counter, enable the SysTick interrupt, and determine counter status.
(系统设置寄存器即SysTick->CTRL)
- SysTick Reload Value Register (STRVR): The reload value for the counter, used to provide the counter's wrap value.
(计数周期寄存器即SysTick->LOAD,LOAD值等于period-1)
- SysTick Current Value Register (STCVR): The current value of the counter.
(当前计数值寄存器即SysTick->VAL)
//暂停看门狗
WDT_A_holdTimer( void );
//使能浮点运算单元
void FPU_enableModule ( void );
/*常用Systick相关函数*/
//SysTick使失能函数
void SysTick_enableModule (void);
void SysTick_disableModule (void);
//SysTick中断使失能函数
void SysTick_enableInterrupt (void);
void SysTick_disableInterrupt (void);
//获取Counter周期、当前值函数
uint32_t SysTick_getPeriod (void);
uint32_t SysTick_getValue (void);
//设定Counter周期函数
void SysTick_setPeriod (uint32_t period);
//注册注销SysTick中断向量函数
void SysTick_registerInterrupt (void(∗intHandler)(void));
void SysTick_unregisterInterrupt (void);
系统时钟树
需要知道的内容:
clock resources(时钟源):
• LFXTCLK: Low-frequency oscillator (LFXT) that can be used either with low-frequency 32768-Hz watch crystals, standard crystals, resonators, or external clock sources in the 32-kHz or below range. When in bypass mode, LFXTCLK can be driven with an external square wave signal in the 32-kHz or below range.
( 低频振荡器(LFXT)可以与32kHz或以下范围的低频32768-Hz手表晶体,标准晶体,谐振器或外部时钟源一起使用。 在旁路模式下,可以使用32kHz或更低范围内的外部方波信号来驱动LFXTCLK。 )
• HFXTCLK: High-frequency oscillator (HFXT) that can be used with standard crystals or resonators in the 1-MHz to 48-MHz range. When in bypass mode, HFXTCLK can be driven with an external square wave signal.
( 高频振荡器(HFXT),可与1MHz至48MHz范围内的标准晶体或谐振器一起使用。 在旁路模式下,可以使用外部方波信号驱动HFXTCLK。 )
• DCOCLK: Internal digitally controlled oscillator (DCO) with programmable frequencies and 3-MHz frequency by default
( 内部数控振荡器(DCO),默认情况下具有可编程频率和3 MHz频率 )
• VLOCLK: Internal very-low-power low-frequency oscillator (VLO) with 9.4-kHz typical frequency
( 内部超低功耗低频振荡器(VLO),典型频率为9.4kHz )
• REFOCLK : Internal, low-power low-frequency oscillator (REFO) with selectable 32.768-kHz or 128-kHz typical frequencies
( 内部低功耗低频振荡器(REFO),具有可选的32.768 kHz或128 kHz典型频率 )
• MODCLK: Internal low-power oscillator with 25-MHz typical frequency
( 内部低功耗振荡器,典型频率为25MHz )
• SYSOSC: Internal oscillator with 5-MHz typical frequency
( 内部振荡器,具有5-MHz典型频率 )
system clock signals(时钟信号):
•ACLK: Auxiliary clock. ACLK is software selectable as LFXTCLK, VLOCLK, or REFOCLK. ACLK can be divided by 1, 2, 4, 8, 16, 32, 64, or 128. ACLK is software selectable by individual peripheral modules. ACLK is restricted to maximum frequency of operation of 128 kHz.
( 辅助时钟。 ACLK可通过软件选择为LFXTCLK,VLOCLK或REFOCLK。 ACLK可以除以1、2、4、8、16、32、64或128。ACLK是可由各个外围模块选择的软件。 ACLK的最大工作频率限制为128 kHz。 )
• MCLK: Master clock. MCLK is software selectable as LFXTCLK, VLOCLK, REFOCLK, DCOCLK,MODCLK, or HFXTCLK. MCLK can be divided by 1, 2, 4, 8, 16, 32, 64, or 128. MCLK is used by the CPU and peripheral module interfaces, as well as, used directly by some peripheral modules.
( 主时钟。 MCLK可通过软件选择为LFXTCLK,VLOCLK,REFOCLK,DCOCLK,MODCLK或HFXTCLK。 MCLK可以除以1、2、4、8、16、32、64或128。MCLK由CPU和外围模块接口使用,以及直接由某些外围模块使用。 )
• HSMCLK: Subsystem master clock. HSMCLK is software selectable as LFXTCLK, VLOCLK,REFOCLK, DCOCLK, MODCLK, HFXTCLK. HSMCLK can be divided by 1, 2, 4, 8, 16, 32, 64, or 128.HSMCLK is software selectable by individual peripheral modules.
( 子系统主时钟。 HSMCLK可以选择为LFXTCLK,VLOCLK,REFOCLK,DCOCLK,MODCLK,HFXTCLK。 HSMCLK可以被1、2、4、8、16、32、64或128分频。HSMCLK是可由各个外围模块选择的软件。 )
• SMCLK: Low-speed subsystem master clock. SMCLK uses the HSMCLK clock resource selection for its clock resource. SMCLK can be divided independently from HSMCLK by 1, 2, 4, 8, 16, 32, 64, or 128. SMCLK is limited in frequency to half of the rated maximum frequency of HSMCLK. SMCLK is software selectable by individual peripheral modules.
(低速子系统主时钟。 SMCLK将HSMCLK时钟资源选择用于其时钟资源。 可以将SMCLK与HSMCLK分别分频为1、2、4、8、16、32、64或128。SMCLK的频率限制为HSMCLK额定最大频率的一半。 SMCLK是可由各个外围模块选择的软件。)
• BCLK:Low-speed backup domain clock. BCLK is software selectable as LFXTCLK and REFOCLK and is used primarily in the backup domain. BCLK is restricted to a maximum frequency of 32.768 kHz.
( 低速备份域时钟。 BCLK是软件可选的LFXTCLK和REFOCLK,主要用于备份域。 BCLK的最大频率限制为32.768 kHz。 )
上述为MSP432时钟系统介绍的截图,为了便于区分已经利用不同的颜色标出了不同的时钟总线。
根据上图可总结出如下时钟信号和时钟源的关系:
时钟源时钟信号 | ACLK | MCLK | HSMCLK | SMCLK | BCLK | 能否直接被其他外设使用 |
---|---|---|---|---|---|---|
LFXTCLK | √ | √ | √ | √ | √ | √ |
VLO | √ | √ | √ | √ | - | √ |
REFO | √ | √ | √ | √ | √ | √ |
DCOCLK | - | √ | √ | √ | - | - |
MODOSC | - | √ | √ | √ | - | √ |
HFXTCLK | - | √ | √ | √ | - | - |
SYSOSC | - | - | - | - | - | √ |
常用系统时钟函数
/*常用时钟树相关函数*/
//获取各种外部时钟源的频率(用于调试时钟树很方便)
uint32_t CS_getACLK(void);
uint32_t CS_getBCLK(void);
uint32_t CS_getHSMCLK(void);
uint32_t CS_getMCLK(void);
uint32_t CS_getSMCLK(void);
//时钟信号初始化(用于设置时钟分频)
void CS_initClockSignal(uint32_t selectedClockSignal, uint32_t clockSource, uint32_t clockSourceDivider);
//设置DCOCLK频率范围中心(简单确定DCOCLK频率范围,后面需要加上一个频率设置函数确定具体频率)
void CS_setDCOCenteredFrequency (uint32_t dcoFreq);
//设置DCOCLK频率值
void CS_setDCOFrequency (uint32_t dcoFrequency);
Digital I/O(数字输入输出)
Digital I/O介绍
虽然名字不同,但是和STM中的GPIO几乎完全相同。
甚至在DriverLib库的手册中直接用了GPIO的写法(诶,我们不装了,摊牌了,就是一样的!)
不过有一点值得注意的是一个叫做外设GPIO的东西,它其实和GPIO完全不是一个东西。通俗的讲其实它是为其他的需要引脚来进行输入输出的外设选择了其需要的引脚并配置为相应的模式。例如IIC、SPI、PWM等等。
正是因此所以前面我说的内容其实并不严谨。应该是说:在通用输入输出功能上,他们虽然名字不同,但是和STM中的GPIO几乎完全相同。
但是仔细想一下,这两个手册中表现出的理解似乎并不一样:GPIO更像是功能性的叙述,说明该功能为通用输入输出;Digital I/O更像是硬件上的描述,只要是需要进行“数字输入输出“的功能都需要用到Digital I/O。
至于DriverLib中的相关函数,我对它们的评价是:通俗易懂。
真的就通俗易懂到只要翻译一下名字就知道是干什么的程度。
常用GPIO函数汇总
//GPIO模式设置
void GPIO_setAsOutputPin(uint_fast8_t selectedPort,uint_fast16_t selectedPins);
void GPIO_setAsInputPin(uint_fast8_t selectedPort, uint_fast16_t selectedPins);
void GPIO_setAsInputPinWithPullDownResistor(uint_fast8_t selectedPort,
uint_fast16_t selectedPins);
void GPIO_setAsInputPinWithPullUpResistor(uint_fast8_t selectedPort,
uint_fast16_t selectedPins);
//外设GPIO设置
void GPIO_setAsPeripheralModuleFunctionInputPin(uint_fast8_t selectedPort,uint_fast16_t selectedPins,uint_fast8_t mode);//模式参数:GPIO_PRIMARY_MODULE_FUNCTION/GPIO_SECONDARY_MODULE_FUNCTION/GPIO_TERTIARY_MODULE_FUNCTION
void GPIO_setAsPeripheralModuleFunctionOutputPin(uint_fast8_t selectedPort,uint_fast16_t selectedPins,uint_fast8_t mode);//模式参数:GPIO_PRIMARY_MODULE_FUNCTION/GPIO_SECONDARY_MODULE_FUNCTION/GPIO_TERTIARY_MODULE_FUNCTION
//GPIO输出设置
void GPIO_setOutputHighOnPin(uint_fast8_t selectedPort, uint_fast16_t
selectedPins);
void GPIO_setOutputLowOnPin(uint_fast8_t selectedPort, uint_fast16_t
selectedPins);
void GPIO_toggleOutputOnPin(uint_fast8_t selectedPort, uint_fast16_t
selectedPins);
//GPIO输入读取
uint8_t GPIO_getInputPinValue ( uint_fast8_t selectedPort, uint_fast16_t
selectedPins );//返回:GPIO_INPUT_PIN_HIGH/GPIO_INPUT_PIN_LOW
//GPIO中断设置
void GPIO_clearInterruptFlag ( uint_fast8_t selectedPort, uint_fast16_t
selectedPins );
void GPIO_disableInterrupt ( uint_fast8_t selectedPort, uint_fast16_t
selectedPins );
void GPIO_enableInterrupt ( uint_fast8_t selectedPort, uint_fast16_t
selectedPins );
void GPIO_interruptEdgeSelect ( uint_fast8_t selectedPort, uint_fast16_t
selectedPins, uint_fast8_t edgeSelect );//模式参数:GPIO_HIGH_TO_LOW_TRANSITION/GPIO_LOW_TO_HIGH_TRANSITION
uint_fast16_t GPIO_getEnabledInterruptStatus ( uint_fast8_t selectedPort );//返回端口引脚的逻辑或结果
//中断向量处理
void GPIO_registerInterrupt ( uint_fast8_t selectedPort, void(∗)(void) intHandler )
void GPIO_unregisterInterrupt ( uint_fast8_t selectedPort );//注销中断向量
定时器
定时器介绍
我认为MSP432与ST的定时器区别最大的地方在于它将32位定时器和16位定时器分开来,将PWM的功能仅仅赋予16位定时器。
本次比赛并未用到过32位定时器,因此我也不好多说,此处介绍我们用到的16位定时器的部分功能。
需要知道的东西:
- 定时器模块图:
- UPMODE是从0计数到CCR0
- UPDOWNMODE是先递增计数到CCR0再递减计数到0,其中CCR0=period*1/2
- CONTINOUSMODE是从0计数到0xFFFF
定时器中并没有影子寄存器的说法,但是其实官方默认是具有类似ST中影子寄存器的功能的:
- UPMODE中的说明:
- UPDOWNMODE中的说明:
定时器函数
/*相关结构体*/
typedef struct _Timer_A_ContinuousModeConfig
{
uint_fast16_t clockSource;
uint_fast16_t clockSourceDivider;
//注意:此处的分频是指在主频经过分频后得到的对应时钟频率的基础上进行分频
uint_fast16_t timerInterruptEnable_TAIE;
uint_fast16_t timerClear;
} Timer_A_ContinuousModeConfig;
typedef struct _Timer_A_UpDownModeConfig
{
uint_fast16_t clockSource;
uint_fast16_t clockSourceDivider;
uint_fast16_t timerPeriod;
uint_fast16_t timerInterruptEnable_TAIE;
uint_fast16_t captureCompareInterruptEnable_CCR0_CCIE;
uint_fast16_t timerClear;
} Timer_A_UpDownModeConfig;
typedef struct _Timer_A_UpModeConfig
{
uint_fast16_t clockSource;
uint_fast16_t clockSourceDivider;
uint_fast16_t timerPeriod;
uint_fast16_t timerInterruptEnable_TAIE;
uint_fast16_t captureCompareInterruptEnable_CCR0_CCIE;
uint_fast16_t timerClear;
} Timer_A_UpModeConfig;
typedef struct _Timer_A_PWMConfig
{
uint_fast16_t clockSource;
//TIMER_A_CLOCKSOURCE_EXTERNAL_TXCLK
//TIMER_A_CLOCKSOURCE_ACLK
//TIMER_A_CLOCKSOURCE_SMCLK
//TIMER_A_CLOCKSOURCE_INVERTED_EXTERNAL_TXCLK
uint_fast16_t clockSourceDivider;
//TIMER_A_CLOCKSOURCE_DIVIDER_1,2,3,4,5,6,7,8,10,12,14
//TIMER_A_CLOCKSOURCE_DIVIDER_16,20,24,28,32,40,48,56,64
uint_fast16_t timerPeriod;
//selects the desired timer period
uint_fast16_t compareRegister;
//TIMER_A_CAPTURECOMPARE_REGISTER_0,1,2,3,4,5,6
uint_fast16_t compareOutputMode;
//TIMER_A_OUTPUTMODE_OUTBITVALUE,
//TIMER_A_OUTPUTMODE_SET,
//TIMER_A_OUTPUTMODE_TOGGLE_RESET,
//TIMER_A_OUTPUTMODE_SET_RESET
//TIMER_A_OUTPUTMODE_TOGGLE,
//TIMER_A_OUTPUTMODE_RESET,
//TIMER_A_OUTPUTMODE_TOGGLE_SET,
//TIMER_A_OUTPUTMODE_RESET_SET
uint_fast16_t dutyCycle;
//specifies the dutycycle for the generated waveform
} Timer_A_PWMConfig;
/*相关函数*/
//三种计数模式配置函数
void Timer_A_configureContinuousMode (uint32_t timer, const Timer_A_ContinuousModeConfig ∗config);
void Timer_A_configureUpDownMode (uint32_t timer, const Timer_A_UpDownModeConfig ∗config);
void Timer_A_configureUpMode (uint32_t timer, const Timer_A_UpModeConfig ∗config);
//PWM相关函数
void Timer_A_generatePWM (uint32_t timer, const Timer_A_PWMConfig ∗config);
void Timer_A_setCompareValue (uint32_t timer, uint_fast16_t compareRegister,uint_fast16_t compareValue);
//中断相关函数
void Timer_A_enableInterrupt (uint32_t timer);
void Timer_A_disableInterrupt (uint32_t timer);
void Timer_A_clearInterruptFlag (uint32_t timer);
void Timer_A_registerInterrupt (uint32_t timer, uint_fast8_t interruptSelect, void(∗intHandler)(void));
void Timer_A_unregisterInterrupt (uint32_t timer, uint_fast8_t interruptSelect);
系统中断(NVIC)
一点小小想法
PS:暂且将Interrupt开头的函数称为系统中断函数,而各个外设中的中断函数成为外设中断函数。
学习中断函数的时候能感受到这个库的逻辑和HAL库最大的差别在于对中断向量的处理:
HAL库将中断处理函数全部写好了,给用户保留了中断回调函数作为接口,开机载入中断向量表的时候会将所有的中断处理函数都作为中断向量加载好,接着在中断处理函数中调用回调函数进而实现将用户代码加入中断中的目的。而SDK的中断向量表从一开始就是空的,用户需要自行编写中断处理函数,并且自行注册中断向量,进而实现发生中断时对中断内部代码的调用。
说简单点就是HAL库棒用户填好了中断向量表,而SDK则需要用户自行填写中断向量表,两种方式自然各有利弊。
HAL库最大的好处就是它简单,使用的时候很简单,只需要写一个回调函数就能完成中断内部函数的书写,对新手友好。但是我个人认为最大的缺点在于没有给新手一个好的引导,这也是我用了SDK的中断部分以后最大的感受:受益匪浅。这种函数的组织方式能让人更好的感受到有一个叫做“中断向量表”的东西一直在指引着程序,让程序知道发生了中断以后该执行什么函数。
常用系统中断函数
/*中断相关函数*/
void Interrupt_disableInterrupt (uint32_t interruptNumber);
void Interrupt_enableInterrupt (uint32_t interruptNumber);
void Interrupt_registerInterrupt(uint32_t interruptNumber,void (*intHandler)(void));
void Interrupt_unregisterInterrupt(uint32_t interruptNumber);
注意:
- 使能某中断时必须同时调用外设中断使能函数和系统中断使能函数。
- 各个外设对应的注册中断向量函数其实内部调用了系统中断使能函数和系统注册中断向量函数
串口(UART)
串口介绍
其实串口没啥好介绍的,就是为了标题能整整齐齐所以写了这里。
其实还是看到了一些看起来很新奇的功能模块的,只不过还没用起来过,所以也不好说什么。
或许以后再次接触的时候会用到呢,这里留个坑吧。
看到的有趣功能:
- Automatic Baud-Rate Detection (自动波特率检测?)
- Automatic Error Detection (自动错误侦测?)
常用串口函数
/*串口配置结构体*/
typedef struct _eUSCI_eUSCI_UART_ConfigV1
{
uint_fast8_t selectClockSource;
uint_fast16_t clockPrescalar;//对应取值见设备用户指南(DEVICE USER GUIDE)
uint_fast8_t firstModReg; //对应取值见设备用户指南(DEVICE USER GUIDE)
uint_fast8_t secondModReg; //对应取值见设备用户指南(DEVICE USER GUIDE)
uint_fast8_t parity;
uint_fast16_t msborLsbFirst;
uint_fast16_t numberofStopBits;
uint_fast16_t uartMode;
uint_fast8_t overSampling;
uint_fast16_t dataLength;
} eUSCI_UART_ConfigV1;
结构体各部分定义及其取值:
关于上述结构体中注释的三个变量的取值方式:
在USER GUID中查表可得对应取值:
/*串口函数*/
//使能、失能串口
void UART_enableModule (uint32_t moduleInstance);
void UART_disableModule (uint32_t moduleInstance);
//初始化串口
bool UART_initModule (uint32_t moduleInstance, const eUSCI_UART_ConfigV1 ∗config);
//串口收发数据(单字节形式)
void UART_transmitData (uint32_t moduleInstance, uint_fast8_t transmitData);
uint8_t UART_receiveData (uint32_t moduleInstance);
//使能、失能串口中断
void UART_enableInterrupt (uint32_t moduleInstance, uint_fast8_t mask);
void UART_disableInterrupt (uint32_t moduleInstance, uint_fast8_t mask);
//清除中断标志位
void UART_clearInterruptFlag (uint32_t moduleInstance, uint_fast8_t mask);
//注册、注销中断向量
void UART_registerInterrupt (uint32_t moduleInstance, void(∗intHandler)(void));
void UART_unregisterInterrupt (uint32_t moduleInstance);
需要注意的内容:
- UART_initModule()函数并不能使能串口,手册说明如下:
- UART_receiveData()函数只有在没有使能串口中断的时候才会轮询中断标志位,也就是说会阻塞程序的运行;当使能中断后就不会再轮询标志位了(因为标志位的变化会引起串口中断,用户可以在中断中进行数据的处理)。
- 串口的中断接收没法进行断点式的调试,毕竟接收函数并没有轮询标志位,也就不会等着下一个字节数据的到来,信号在线路中传输是不会等待你下断点调试的。
工程函数总结
在使用的过程中,为了使用方便,我们将我们用到的函数进行了模块化的封装,对应文件内容如下:
user.c
//
// Created by ZheWana on 2021/5/26.
//
#include "user.h"
void UARTRetargetInit(void) {
GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P1, GPIO_PIN2 | GPIO_PIN3,
GPIO_PRIMARY_MODULE_FUNCTION);
const eUSCI_UART_ConfigV1 uartConfig =
{
EUSCI_A_UART_CLOCKSOURCE_SMCLK,//选择时钟源
6, //In device guide:UCBRx
8, //In device guide:UCBRFx
0x11, //In device guide:UCBRSx
EUSCI_A_UART_NO_PARITY, //极性设置
EUSCI_A_UART_LSB_FIRST, //设置高低位优先
EUSCI_A_UART_ONE_STOP_BIT, //停止位数
EUSCI_A_UART_MODE, //串口模式
EUSCI_A_UART_OVERSAMPLING_BAUDRATE_GENERATION,
EUSCI_A_UART_8_BIT_LEN //数据长度
};
//配置时钟源,其中SMCLK进行4分频
//主频48000000
//SMCLK为12000000
CS_setDCOCenteredFrequency(CS_DCO_FREQUENCY_48);
CS_setDCOFrequency(48000000);
CS_initClockSignal(CS_SMCLK,CS_DCOCLK_SELECT,CS_CLOCK_DIVIDER_4);
//串口模块初始化以及使能
UART_initModule(EUSCI_A0_BASE, &uartConfig);
UART_enableModule(EUSCI_A0_BASE);
}
//串口重定向函数
int UART_printf(uint32_t moduleInstance, const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
int length;
char buffer[128];
length = vsnprintf(buffer, 128, fmt, ap);
for (int i = 0; i < length; i++)
UART_transmitData(moduleInstance, *(buffer + i));
va_end(ap);
return length;
}
int32_t CNT;
void Encoder_IRQHandler(void) {
uint8_t temp = GPIO_getInputPinValue(GPIO_PORT_P3, GPIO_PIN2);
uint32_t status;
status = MAP_GPIO_getEnabledInterruptStatus(GPIO_PORT_P3);
MAP_GPIO_clearInterruptFlag(GPIO_PORT_P3, status);
if (status & GPIO_PIN3) {
MAP_GPIO_toggleOutputOnPin(GPIO_PORT_P1, GPIO_PIN0);
if (temp == GPIO_INPUT_PIN_HIGH) {
CNT++;
} else if (temp == GPIO_INPUT_PIN_LOW) {
CNT--;
}
}
}
void EncoderInit(void){
//GPIO模式设置
GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P3, GPIO_PIN3);
GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P3, GPIO_PIN2);
//清除中断标志位
GPIO_clearInterruptFlag(GPIO_PORT_P3, GPIO_PIN3);
//中断使能
GPIO_enableInterrupt(GPIO_PORT_P3, GPIO_PIN3);
//中断触发边沿选择
GPIO_interruptEdgeSelect(GPIO_PORT_P3, GPIO_PIN3, GPIO_LOW_TO_HIGH_TRANSITION);
//中断使能以及中断向量注册
Interrupt_enableInterrupt(INT_PORT3);
Interrupt_enableMaster();
Interrupt_registerInterrupt(INT_PORT3, Encoder_IRQHandler);
}
void TIMERA0_IRQHandler(void){
Timer_A_clearInterruptFlag(TIMER_A0_BASE);
/********
*处理函数*
********/
}
void TimerIntuerruptInit(double period){
Timer_A_UpModeConfig Timer={
TIMER_A_CLOCKSOURCE_ACLK,
TIMER_A_CLOCKSOURCE_DIVIDER_1,
(int)(period/1000*32000),
TIMER_A_TAIE_INTERRUPT_ENABLE,
};
Timer_A_configureUpMode(TIMER_A0_BASE,&Timer);
Timer_A_enableInterrupt(TIMER_A0_BASE);
Timer_A_clearInterruptFlag(TIMER_A0_BASE);
Interrupt_enableInterrupt(INT_TA0_N);
Interrupt_enableMaster();
Interrupt_registerInterrupt(INT_TA0_N, TIMERA0_IRQHandler);
Timer_A_startCounter(TIMER_A0_BASE, TIMER_A_UP_MODE);
}
void Delay_ms(int freq, int time) {
SysTick_enableModule();
SysTick_setPeriod(1<<24);
SysTick->VAL=1<<24;
uint32_t a = SysTick_getValue();
while ((a - SysTick_getValue()) < freq / 1000 * time);
SysTick_disableModule();
}
int uartflag = 0;
char ch = 'a';
char buff[5];
double data, p, i, d, a;
int cnt = 0;
void UART_IRQHandler(void) {
buff[cnt] = UART_receiveData(EUSCI_A0_BASE);
cnt++;
if (cnt == 5)cnt = 0;
}
user.h
//
// Created by ZheWana on 2021/5/26.
//
#ifndef TEMPLATE_USER_H
#define TEMPLATE_USER_H
#include "ti/devices/msp432p4xx/driverlib/driverlib.h"
#include "stdio.h"
#include "stdarg.h"
//串口重定向初始化
void UARTRetargetInit(void);
//串口重定向输出函数
int UART_printf(uint32_t moduleInstance, const char *fmt, ...);
//定时器中断处理函数
void TIMERA0_IRQHandler(void);
//定时器中断初始化函数
void TimerIntuerruptInit(double period);
//编码器初始化函数
void EncoderInit(void);
//编码器对应IO中断处理函数
void Encoder_IRQHandler(void);
//毫秒延时函数
void Delay_ms(int freq, int time);
//串口中断回调函数
void UART_IRQHandler(void);
#endif //TEMPLATE_USER_H
后记
因为比赛原因所以学习的其实很仓促,所以很多东西理解的并不好,接下来会找时间系统的好好学习一下的。
路漫漫其修远兮,吾将上下而求索。