【MSP430F5529基于库函数的学习】电赛速学及小车实战

文章目录

  • 前言
  • 一、void SystemClock_Init(void)//系统初始化
    • 时钟系统结构
  • 二、void Counter_Left_Init (void) //编码器计数
    • 设置外部中断
  • 三、void TimerA1Init()//定时器初始化
    • 定时器中断函数
  • 四、void Motor_Left_Init (void)//PWM初始化
    • 解释一下如何产生pwm
    • 补充一个GPIO的规范用法
  • 五、bool UART_Init(uint16_t baseAddress, uint32_t Baudrate)//串口初始化
    • 通信规则
    • 细解一下这里的参数
    • __even_in_range的使用
    • 简单与openmv通讯
  • 六、OLED_Init()//oled初始化
    • 一个发现(和普及I2C原理)
  • 总结
  • 附件

前言

为电赛准备学习的MSP430笔记


提示:主要跟着这个大佬学的

在这里插入图片描述
一张经常要看的图

一、void SystemClock_Init(void)//系统初始化

时钟配置和闪烁的LED

时钟系统结构

时钟系统结构
(1)5个时钟来源
时钟系统模块具有5个时钟来源。
① XT1CLK:低频/高频振荡器,可以使用32768Hz的手表晶振、标准晶体、谐振器或4~32MHz的外部时钟源;
② VLOCLK:内部超低功耗低频振荡器,典型频率12kHz;
③ REFOCLK:内部调整低频参考振荡器,典型值为32768Hz;
④ DCOCLK:内部数字时钟振荡器,可由FLL稳定后得到;
⑤ XT2CLK:高频振荡器,可以是标准晶振、谐振器或4~32MHz的外部时钟源。
(2)3个时钟信号
时钟系统模块可以产生3个时钟信号供CPU和外设使用。
① ACLK:辅助时钟(Auxiliary Clock)。可以通过软件选择XT1CLK、REFOCLK、VLOCLK、DCOCLK、DCOCLKDIV或XT2CLK(当XT2CLK可用时)。DCOCLKDIV是FLL模块内DCOCLK经过1/2/4/8/16/32分频后获得的。ACLK主要用于低速外设。ACLK可以再进行1/2/4/8/16/32分频,ACLK/n 就是ACLK 经过1/2/4/8/16/32分频后得到的,也可以通过外部引脚进行输出。
② MCLK:主时钟(Master Clock)。MCLK的时钟来源与ACLK相同,MCLK专门供CPU使用,MCLK配置得越高,CPU的执行速度就越快,功耗就越高。一旦关闭MCLK,CPU也将停止工作,因此在超低功耗系统中可以通过间歇启用MCLK的方法降低系统功耗。MCLK也可经1/2/4/8/16/32分频后供CPU使用。
③ SMCLK:子系统时钟(Subsystem Master Clock)。SMCLK的时钟来源与ACLK相同,SMCLK主要用于高速外设,SMCLK也可以再进行1/2/4/8/16/32分频。

MSP430具有高达25Mhz的主频,让我们来配置它

//将主时钟MCLK,子系统时钟SMCLK设为25Mhz,MCLK主要用于CPU,SMCLK主要用于高速外设
//将辅助时钟ACLK设为32768Hz,主要用于低速外设
void SystemClock_Init(void)
{
    PMM_setVCore(PMM_CORE_LEVEL_3);     //高主频工作需要较高的核心电压

    //XT1振荡器的引脚复用  P5.4 XIN输入 P5.5 XOUT输出 选择单片机内部的晶振
    GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P5, GPIO_PIN4);
    GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P5, GPIO_PIN5);

    //起振XT1  若在LF工作下的XT1振荡器为32768hz的低频晶振,与之相匹配为12pf的电容    XCAP(0: 2pf ,1: 5.5pf, 2: 8,5pf, 3:12pf )
    UCS_turnOnLFXT1(UCS_XT1_DRIVE_3,UCS_XCAP_3);

    //XT2引脚复用   P5.2 XIN输入 P5.5 XOUT输出 板载XT2晶振为CSTCR4M00G15L99,4MHz
    GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P5, GPIO_PIN2);
    GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P5, GPIO_PIN3);

    //起振XT2
    UCS_turnOnXT2(UCS_XT2_DRIVE_4MHZ_8MHZ);

    //XT2作为FLL(锁频环)的时钟源,输出为DCOCLK(内部数字时钟振荡器),8分频                      先8分频,再50倍频 4MHz / 8 * 50 = 25MHz
    UCS_initClockSignal(UCS_FLLREF, UCS_XT2CLK_SELECT, UCS_CLOCK_DIVIDER_8);
    //用于设置锁相环倍频系数,第一个系数为目标主时钟的频率 单位kHz,第二个系数为= 第一个系数/FLL的频率 (既刚刚得到的4Mhz/8)  50 = 25000khz/(0.5M)  1000k= 1M 1M =10^6khz
    UCS_initFLLSettle(25000, 50);

    //XT1作为ACLK时钟源 = 32768Hz 1分频= /1
    UCS_initClockSignal(UCS_ACLK, UCS_XT1CLK_SELECT, UCS_CLOCK_DIVIDER_1);

    //DCOCLK作为MCLK时钟源 = 25MHz
    UCS_initClockSignal(UCS_MCLK, UCS_DCOCLK_SELECT, UCS_CLOCK_DIVIDER_1);

    //DCOCLK作为SMCLK时钟源 = 25MHz
    UCS_initClockSignal(UCS_SMCLK, UCS_DCOCLK_SELECT, UCS_CLOCK_DIVIDER_1);

    //设置外部时钟源的频率,使得在调用UCS_getMCLK, UCS_getSMCLK 或 UCS_getACLK时可得到正确值 (XT1CLK_frequency,XT2CLK_frequency)
    UCS_setExternalClockSource(32768, 4000000);
}

二、void Counter_Left_Init (void) //编码器计数

GPIO

电机编码器的线数为11(一圈方波数)30(减速比)=330
线数太低了,我们使用4倍频来使它加倍,330
4=1320
我们需要在AB相的上升下降沿都计数(相当于原来的4倍)

现在我们用外部中断来实现编码器计数

设置外部中断

void Counter_Left_Init (void)
{
    //配置时,先配置功能选择寄存器PxSEL,
    //若为I/O端口功能,则继续配置方向寄存器PxDIR;
    //若为输入,则继续配置中断使能寄存器PxIE;
    //若允许中断,则继续配置中断触发沿选择寄存器PxIES。
    //只有P1 和P2 有中断功能

    //P1.3 P1.6 上拉输入并使能interrupt enabled    使能寄存器需和输出寄存器配合使用,才能完成上拉/下拉电阻的配置。
    GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P1,GPIO_PIN3 +GPIO_PIN6);
    GPIO_enableInterrupt(GPIO_PORT_P1,GPIO_PIN3 +GPIO_PIN6);

    //设置中断类型 Hi/Lo edge
    GPIO_selectInterruptEdge(GPIO_PORT_P1,GPIO_PIN3,GPIO_HIGH_TO_LOW_TRANSITION|GPIO_LOW_TO_HIGH_TRANSITION);
    GPIO_selectInterruptEdge(GPIO_PORT_P1,GPIO_PIN6,GPIO_HIGH_TO_LOW_TRANSITION|GPIO_LOW_TO_HIGH_TRANSITION);

    //清除中断标志位 IFG cleared
    GPIO_clearInterrupt(GPIO_PORT_P1,GPIO_PIN3 +GPIO_PIN6);

    //启用可屏蔽中断(具有中断功能的片上外设产生)
    _BIS_SR(GIE);

}

中断函数
在这里插入图片描述
在这里插入图片描述

#pragma vector=PORT1_VECTOR     // P1口中断源
__interrupt
void Port_1 (void)
{
//    if(GPIO_getInterruptStatus (GPIO_PORT_P1, GPIO_PIN3)||GPIO_getInterruptStatus (GPIO_PORT_P1, GPIO_PIN6))
//    {
//        Counter_Left++;
//        GPIO_clearInterrupt(GPIO_PORT_P1,GPIO_PIN3 +GPIO_PIN6);  
//    }
    _EINT();//恢复总的中断允许,避免中断处理延迟
    if(GPIO_getInterruptStatus(GPIO_PORT_P1, GPIO_PIN3))//当发生中断
    {
        Counter_Left++;
        GPIO_clearInterrupt(GPIO_PORT_P1,GPIO_PIN3);
    }
    if(GPIO_getInterruptStatus(GPIO_PORT_P1, GPIO_PIN6))
    {
        Counter_Left++;
        GPIO_clearInterrupt(GPIO_PORT_P1,GPIO_PIN6);
    }
}

三、void TimerA1Init()//定时器初始化

定时器A
我们想实现每秒sec加1

设得中断频率为25MHz / 10 / 25000 = 100Hz //即每秒刷新100下,0.01s定时
一共两个中断模式CCR0中断 TAIE中断,一个使能一个不使能
一般使用增计数模式CCR0中断
在这里插入图片描述

定时器A增计数模式CCR0中断

//定时0.01s
void TimerA1Init()
{
    Timer_A_initUpModeParam param = {0};
    param.clockSource = TIMER_A_CLOCKSOURCE_SMCLK; //时钟源选为SMCLK = 25MHz
    param.clockSourceDivider = TIMER_A_CLOCKSOURCE_DIVIDER_10;  //10分频
    param.timerPeriod = 25000-1;    //计数值设为25000 - 1
    param.timerInterruptEnable_TAIE = TIMER_A_TAIE_INTERRUPT_DISABLE;   //不使能 TAIE中断
    param.captureCompareInterruptEnable_CCR0_CCIE = TIMER_A_CCIE_CCR0_INTERRUPT_ENABLE;   //使能CCR0中断
    param.timerClear = TIMER_A_DO_CLEAR;  //把定时器的定时计数器,分频计数器的计数值清零
    param.startTimer = true;     //初始化后立即启动定时器

    //设得中断频率为25MHz / 10 / 25000 = 100Hz
    Timer_A_initUpMode(TIMER_A1_BASE,&param);   //配置定时器A为增计数模式
}

定时器中断函数

在这里插入图片描述
例如我们配置定时器1的0寄存器(在32里应该叫通道)
TIMER_A1_BASE
TIMER1_A0_VECTOR //向量名和中断函数名必须一致
TIMER1_A0_ISR //前面的1 是A1的1

#pragma vector=TIMER1_A0_VECTOR
__interrupt
void TIMER1_A0_ISR (void)
{
    if(n++==100)
    {
        second++;
        n=0;
    }
}

四、void Motor_Left_Init (void)//PWM初始化

定时器A

解释一下如何产生pwm

Timer_A_outputPWM(uint16_t baseAddress, Timer_A_outputPWMParam ∗param)
//计时器A运行在增计数模式产生PWM

为什么说这句话是在增计数模式下呢,我们并没看到配置定时器在增计数模式,所以我们看看这个库函数怎么写的。
在这里插入图片描述
它在第一句把所有位进行了一个清零的操作,然后在第4句将TIMER_A_UP_MODE置1,至此我们知道它将增模式也一起配置了。
已知增计数模式下是将0加到TAxCCR0再重新计数,我们看到它将TAxCCR0置为我们可以设置的时间周期timerPeriod。dutyCycle是什么呢,下面会解释。

然后我们在这里将compareOutputMode设置 复位置位 模式

param.compareOutputMode = TIMER_A_OUTPUTMODE_RESET_SET;

在这里插入图片描述
增计数模式下,定时器比较输出在这里插入图片描述
在这个模式下,我们发现在计数到TAxCCR1时为高电平输出,TAxCCR1~TAxCCR0时为低电平输出,而TAxCCR1就是我们上文未解释的dutyCycle(占空比),当我们将TAxCCR0设为100,TAxCCR1设为50时,那我们的占空比就为50/100 = 50%。

我们想实现电机初始化

P1.2 对应 TA0.1

void Motor_Left_Init (void)
{
    //P1.2 as PWM output
    GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P1, GPIO_PIN2);//P1.2复用输出
	//GPIO_setAsOutputPin (GPIO_PORT_P4,GPIO_PIN0 +GPIO_PIN3 );   //GPIO输出
    //GPIO_setOutputHighOnPin (GPIO_PORT_P4, GPIO_PIN0);  //高电位输出
    //GPIO_setOutputLowOnPin (GPIO_PORT_P4, GPIO_PIN3);  //低电位输出

    //Generate PWM - Timer runs in Up mode
    Timer_A_outputPWMParam param = {0};
    param.clockSource = TIMER_A_CLOCKSOURCE_SMCLK;      // 时钟源选为SMCLK = 25MHz
    param.clockSourceDivider = TIMER_A_CLOCKSOURCE_DIVIDER_1;       //不分频
    //装载值设为1000 - 1
    param.timerPeriod =1000-1;      //时钟周期
    //频率为25M/1/1000 = 25000hz
    //P1.2 对应 TA0.1 故设为TIMER_A_CAPTURECOMPARE_REGISTER_1
    param.compareRegister = TIMER_A_CAPTURECOMPARE_REGISTER_1;      //选择比较寄存器
    param.compareOutputMode = TIMER_A_OUTPUTMODE_RESET_SET;//pwm最大1000
    param.dutyCycle = 0;//这个值compare = 300 就相当于300/1000 30%的占空比
    Timer_A_outputPWM(TIMER_A0_BASE, &param);
}

Timer_A_setCompareValue(uint16_t baseAddress, uint16_t compareRegister, uint16_t
compareValue)
//设置捕获比较寄存器的值

void Motor_SetSpeed_Left(int8_t Speed)
{
	GPIO_setAsOutputPin (GPIO_PORT_P4,GPIO_PIN0 +GPIO_PIN3 );//初始化GPIO输出
	if (Speed >= 0)  //正数 代表正转
	{
   		
   		GPIO_setOutputHighOnPin (GPIO_PORT_P4, GPIO_PIN0);  //高电位输出
    	GPIO_setOutputLowOnPin (GPIO_PORT_P4, GPIO_PIN3);  //低电位输出
		Timer_A_setCompareValue(TIMER_A0_BASE, TIMER_A_CAPTURECOMPARE_REGISTER_1, Speed)
	}
	else
	{
		GPIO_setOutputLowOnPin (GPIO_PORT_P4, GPIO_PIN0);  //高电位输出
    	GPIO_setOutputHighOnPin (GPIO_PORT_P4, GPIO_PIN3);  //低电位输出
		Timer_A_setCompareValue(TIMER_A0_BASE, TIMER_A_CAPTURECOMPARE_REGISTER_1, -Speed)//因为SetCompare要传的是无符号整型数 所以 speed加负号
	}
}

最终输出速度,小车开始转

void Front_Run(void)
{
    Motor_SetSpeed_Left(300);
    Motor_SetSpeed_Right(300);
}

补充一个GPIO的规范用法

在这里插入图片描述
首先我们对引脚配置输入或是输出

GPIO_setAsOutputPin(uint8_t selectedPort, uint16_t selectedPins);
GPIO_setAsInputPin(uint8_t selectedPort, uint16_t selectedPins);
GPIO_setAsInputPinWithPullDownResistor(uint8_t selectedPort, uint16_t selectedPins);
GPIO_setAsInputPinWithPullUpResistor(uint8_t selectedPort, uint16_t selectedPins);
GPIO_setDriveStrength(uint8_t selectedPort, uint16_t selectedPins, uint8_t
driveStrength);
GPIO_setAsPeripheralModuleFunctionOutputPin(uint8_t selectedPort, uint16_t
selectedPins);
GPIO_setAsPeripheralModuleFunctionInputPin(uint8_t selectedPort, uint16_t
selectedPins);

GPlO引脚可以被配置为在外设模块中操作,通过使用配置GPIO分配功能

GPIO_setOutputHighOnPin(uint8_t selectedPort, uint16_t selectedPins);
GPIO_setOutputLowOnPin(uint8_t selectedPort, uint16_t selectedPins);
GPIO_toggleOutputOnPin(uint8_t selectedPort, uint16_t selectedPins);
GPIO_getInputPinValue(uint8_t selectedPort, uint16_t selectedPins);

一般在程序的初始化阶段对端口进行配置。
配置时,先配置功能选择寄存器PxSEL,
若为I/O端口功能,则继续配置方向寄存器PxDIR;
若为输入,则继续配置中断使能寄存器PxIE;
若允许中断,则继续配置中断触发沿选择寄存器PxIES。

简单配置电机的两个引脚 ,第一句必不可少

   
    GPIO_setAsOutputPin (GPIO_PORT_P4,GPIO_PIN0 +GPIO_PIN3 );   //GPIO输出
    GPIO_setOutputHighOnPin (GPIO_PORT_P4, GPIO_PIN0);  //高电位输出
    GPIO_setOutputLowOnPin (GPIO_PORT_P4, GPIO_PIN3);  //低电位输出

五、bool UART_Init(uint16_t baseAddress, uint32_t Baudrate)//串口初始化

UART通信
P3.3(TX)和P3.4(RX)为USCI_A0串口
P4.4(TX)和P4.5(RX)为USCI_A1串口

通信规则

如图所示,异步通信字符格式由5个部分组成:一个起始位、7位或8位数据位、一个奇/偶/无校验位、一个地址位和一个或两个停止位。其中,用户可以通过软件设置数据位、停止位的位数,还可以设置奇偶校验位的有无。通过选择时钟源和波特率寄存器的数据来确定传输速率。UCMSB控制位用来设置传输的方向和选择最低位还是最高位先发送。一般情况下,对于UART通信选择先发送最低位。
在这里插入图片描述

USCI_A_UART_clearInterrupt(uint16_t baseAddress, uint8_t mask)
//清除UART中断源,使其不再断言。当使用中断向量生成器时,最高中断标志将自动清除
USCI_A_UART_enableInterrupt(uint16_t baseAddress, uint8_t mask)
//启用UART中断

细解一下这里的参数

huart.parity = USCI_A_UART_NO_PARITY;
//设置奇偶校验位,USCI_A_UART_ODD_PARITY奇校验    USCI_A_UART_EVEN_PARITY偶校验  USCI_A_UART_NO_PARITY 无校验位
huart.msborLsbFirst = USCI_A_UART_LSB_FIRST;
//设置最低最低位优先或最高位优先的数据发送和接收方式 通常我们接收数据中的最低位
//LSB(Least Significant Bit)是“最低有效位”。MSB(Most Significant Bit)是“最高有效位”。
huart.numberofStopBits = USCI_A_UART_ONE_STOP_BIT;
//设置停止位 USCI_A_UART_ONE_STOP_BIT 一位USCI_A_UART_TWO_STOP_BITS 两位
huart.uartMode = USCI_A_UART_MODE;
//选择模式 选取默认的异步通讯模式 当三个或多个设备通信时,
USCI支持空闲行    USCI_A_UART_IDLE_LINE_MULTI_PROCESSOR_MODE和
地址位多处理器通信格式    USCI_A_UART_ADDRESS_BIT_MULTI_PROCESSOR_MODE
还一个模式为自动波特率检测	USCI_A_UART_AUTOMATIC_BAUDRATE_DETECTION_MODE

第一个参数为选择串口基地址,第二个参数为波特率

bool UART_Init(uint16_t baseAddress, uint32_t Baudrate)
{
    float UART_Temp = 0;

    USCI_A_UART_initParam huart = {0};

    //将所用引脚复用为UART模式
    if(baseAddress == USCI_A0_BASE)         //P3.3, P3.4 = USCI_A0 TXD/RXD
    {
        GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P3, GPIO_PIN3);
        GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P3, GPIO_PIN4);
    }
    else if(baseAddress == USCI_A1_BASE)    //P4.4, P4.5 = USCI_A1 TXD/RXD
    {
        GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P4, GPIO_PIN4);
        GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P4, GPIO_PIN5);
    }
    //当目标波特率较低时,UART选用时钟源为ACLK,反之选择SMCLK
    //调用UCS_getACLK/UCS_getSMCLK前需正确调用UCS_setExternalClockSource函数,我已加到SystemClock_Init函数中
    if(Baudrate <= 9600)
    {
        huart.selectClockSource = USCI_A_UART_CLOCKSOURCE_ACLK;
        UART_Temp = (float)UCS_getACLK()/Baudrate;
    }
    else
    {
        huart.selectClockSource = USCI_A_UART_CLOCKSOURCE_SMCLK;
        UART_Temp = (float)UCS_getSMCLK()/Baudrate;
    }

    if(UART_Temp < 16)  //当分频因子小于16时,采用低频波特率设置
        huart.overSampling = USCI_A_UART_LOW_FREQUENCY_BAUDRATE_GENERATION;
    else    //反之,采用过采样波特率设置
    {
        huart.overSampling = USCI_A_UART_OVERSAMPLING_BAUDRATE_GENERATION;
        UART_Temp /= 16;
    }

    huart.clockPrescalar = (int)UART_Temp;

    if(huart.overSampling == USCI_A_UART_LOW_FREQUENCY_BAUDRATE_GENERATION)
    {   //低频波特率设置   UCBRSx
        huart.secondModReg = (int)((UART_Temp - huart.clockPrescalar) * 8);
    }
    else
    {   //过采样波特率设置 UCBRFx
        huart.firstModReg = (int)((UART_Temp - huart.clockPrescalar) * 16);
    }

    huart.parity = USCI_A_UART_NO_PARITY;
    huart.msborLsbFirst = USCI_A_UART_LSB_FIRST;
    huart.numberofStopBits = USCI_A_UART_ONE_STOP_BIT;
    huart.uartMode = USCI_A_UART_MODE;

    if (STATUS_FAIL == USCI_A_UART_init(baseAddress, &huart)) //如果成功返回一个STATUS_SUCCESS
    {   //初始化对应串口
        return STATUS_FAIL;
    }

    //Enable UART module for operation 使能对应串口
    USCI_A_UART_enable(baseAddress);

    //Enable Receive Interrupt 启用串口中断
    USCI_A_UART_clearInterrupt(baseAddress, USCI_A_UART_RECEIVE_INTERRUPT);
    USCI_A_UART_enableInterrupt(baseAddress, USCI_A_UART_RECEIVE_INTERRUPT);

    return STATUS_SUCCESS;
}

串口中断函数

USCI_A_UART_transmitData(uint16_t baseAddress, uint8_t transmitData)
//通过UART模块传输一个字节
USCI_A_UART_receiveData(uint16_t baseAddress)
//接收一个已发送到UART模块的字节。

下面实现将接收到的字符回传 接收一个字符就回发一个

#pragma vector=USCI_A0_VECTOR
__interrupt void USCI_A0_ISR (void)
{
    uint8_t receivedData = 0;
    switch (__even_in_range(UCA0IV,4))
    {
        //Vector 2 - RXIFG
        case 2:
            receivedData = USCI_A_UART_receiveData(USCI_A0_BASE);
            USCI_A_UART_transmitData(USCI_A0_BASE,receivedData);
            break;
        default:
            break;
    }
}

__even_in_range的使用

MSP430之__even_in_range
使用__even_in_range 的好处是可以生成效率比较高的代码,在判断多中断源的中断的来源时可以使用此函数。
原型:unsigned short __even_in_range(unsigned short value, unsignedshort upper_limit);

功能:只能与switch 语句结合使用,判断value 是否为偶数且小于等于upper_limit。

简单与openmv通讯

之前已经配置好了串口,
在库函数中,没有相关的函数配置发送数据位数。只在注释里找到。

在这里插入图片描述
从手册里发现默认是8位数据位,
在这里插入图片描述
所以我们msp430串口的相关配置是:8位数据位,无奇偶校验,1位停止位

UART_Init(USCI_A1_BASE, 115200);//做一个115200的初始化

同样,我们在openmv的也进行相同操作

from pyb import UART
uart = UART(3,115200)   #定义串口3变量 #P4 P5
uart.init(115200, bits=8, parity=None, stop=1) # init with given parameters
# 8位数据位 无奇偶校验 1位停止位

最后openmv的数据传给msp430

uart.write(str(output))

我们要实现在openmv的ide里知道是否已经传到msp430,所以我们打印从msp430回传的数据

def recive_data():
    global uart
    if uart.any():
        tmp_data = uart.readline();
        print(tmp_data)
 recive_data();

六、OLED_Init()//oled初始化

库函数I2C驱动OLED屏幕
我们用四针脚的oled来显示,5529芯片上的资源有
P3.0 SDA //P3.1SCL
P4.1SDA //P4.2SCL
看上面的博客的需要改端口的在这可以改
在这里插入图片描述
也可以参考下面这个博客
OLED模块//用这个可以点亮 试过
然后在这个位置修改
在这里插入图片描述

一个发现(和普及I2C原理)

先搞懂一下I2C协议,这个博主讲的非常明白
I2C协议靠这16张图彻底搞懂(超详细)
然后我从发现P3.5 P3.6在芯片手册上明明没有标注有SDA功能,却可以当作SDA,SCL来用,于是深究这个问题,这个是类似的博客发的驱动oled代码
在这里插入图片描述
我先找到一篇博客,TI - MCU - MSP430使用指南14 -> I2C通信(eUSCI),上面说eUSCI_B有追加IIC的功能,手册上也雀实有,不过还是没有讲能用的资源有多少,在这里插入图片描述
于是我开始回到GPIO的引脚上思索这个问题,SDA是双向时钟线在这里插入图片描述
也就意味着双方的两个引脚必须都要有写和读的功能,而MSP430所有的引脚都有写和读的功能,所以我觉得所有的引脚都可以配置成IIC的SDA、SCL,不过这只是我的一个猜测,具体要是有不对的地方,望指正。
在这里插入图片描述
然后P1~P2还有中断的功能。


总结

以上就是今天要讲的内容,本文仅仅简单介绍了MSP430的使用,至此小车是可以跑起来了,为电赛强制用TI的板子做了一个简单的备战。
最后感谢一下女朋友望月12138写的代码。

附件

以下是找的一些MSP430F5529的资料
链接:https://pan.baidu.com/s/1nGVduyZzR0xHqeAV6XStqA?pwd=dwuv
提取码:dwuv文章来源地址https://www.uudwc.com/A/BnZ0V/

原文地址:https://blog.csdn.net/weixin_56760882/article/details/125841604

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请联系站长进行投诉反馈,一经查实,立即删除!

h
上一篇 2023年07月07日 16:07
【贪心】CF1845 C
下一篇 2023年07月07日 16:10