一、项目介绍
使用MAX78000开发板以软件模拟I2C方式驱动OLED。
1.1、准备开发环境
以MAX78000为核心的开发板,除了FTHR_RevA模式的,还有一款EvKit_V1模式的,因此在MaximSDK中导入从网上下载得到的SDK例程时,注意要修改必要的设置,才能保证示例工程正常运行。我没有仔细验证到底改哪几个是有效的,只是单纯地把所有“EvKit_V1”关键字改为“FTHR_RevA”。设计以下几个文件:
1)工程目录.settings\org.eclipse.cdt.core.prefs文件
environment/project/cdt.managedbuild.toolchain.gnu.cross.base.1028364529/BOARD/value=EvKit_V1
2)工程目录.vscode\settings.json文件
“board”:“EvKit_V1”,
3)工程目录\Makefile文件
BOARD ?= EvKit_V1
4)工程目录\project.mk文件
#BOARD=FTHR_RevA
去掉注释符号“#”即可,或者新追加一行“BOARD=FTHR_RevA”
我是在GPIO例程的基础上进行修改的。
1.2、硬件构成
| 名称 | 型号 | 作用 |
|---|---|---|
| 显示部件 | 0.96寸OLED | 显示调试信息 |
| 主控板 | MAX78000FTHR# | 加载驱动、控制显示内容 |
二、功能的实现
2.1、电气连接
选择接口线少的四线OLED,电气连接如下:
2.2、设计思路(含后期追加的电机控制部分)
使用AIN3(P2.3)和AIN4(P2.4)模拟I2C接口的SCL和SDA,同时,使用板载的SW1和SW2按钮,以GPIO中断的方式,处理后面驱动步进电机时的控制转向和是否转动的动作。并通过OLED和板载的三个颜色的LED显示处理结果。
| 对象 | 作用 |
|---|---|
| SW1 | 切换电机的顺时针转动或者逆时针转动。预定给TMX2209的DIR控制用。 |
| SW2 | 通过标志变量。切换0/1状态,控制定时器3是否输出占空比为50%的PWM波。预定给TMX2209的STEP控制用。 |
| 红色LED | 显示PWM波的输出状态。 |
| 绿色LED | 步进电机顺时针转动状态下的指示灯。 |
| 蓝色LED | 步进电机逆时针转动状态下的指示灯。 |
| P2.7 | 切换步进电机的顺时针转动或者逆时针转动的实际输出控制。接TMX2209的DIR。 |
| P2.6 | 输出控制步进电机步进用的脉冲输出。接TMX2209的STEP。 |
目前测试还没有连接TMC2209。仅仅是变成测试。
2.3、程序代码
主程序如下:
/**
* @file main.c
* @brief GPIO Example
* @details
*/
/***** Includes *****/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include "board.h"
#include "mxc_device.h"
#include "mxc_delay.h"
#include "nvic_table.h"
#include "i2c.h"
#include "tmr.h"
#include "oled.h"
#include "tmc2209.h"
extern MOTOR_DIR_Type motor_dir; // 马达方向, P0.17
extern MOTOR_RUN_Type motor_run; // 马达启停,
/***** SW1中断函数 *****/
uint32_t speed = 2;
void sw1_isr(void* cbdata) {
// //mxc_gpio_cfg_t* cfg = cbdata;
// //MXC_GPIO_OutToggle(cfg->port, cfg->mask);
setDirToggle();
//setSpeed(++speed);
}
/***** SW2中断函数 *****/
void sw2_isr(void* cbdata) {
setRunToggle();
}
void setInputKey(void) {
// 马达转动方向控制按钮
mxc_gpio_cfg_t sw1_pin = {MXC_GPIO0, MXC_GPIO_PIN_2, MXC_GPIO_FUNC_IN, MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIOH};
// 启停定时器3控制按钮,使马达运行转动、停止
mxc_gpio_cfg_t sw2_pin = {MXC_GPIO1, MXC_GPIO_PIN_7, MXC_GPIO_FUNC_IN, MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIOH};
// 设置中断:P0.2- SW1
sw1_pin.pad = MXC_GPIO_PAD_PULL_UP;
sw1_pin.func = MXC_GPIO_FUNC_IN;
sw1_pin.vssel = MXC_GPIO_VSSEL_VDDIOH;
MXC_GPIO_Config(&sw1_pin);
//MXC_GPIO_RegisterCallback(&sw1_pin, sw1_isr, &red_led_pin);
MXC_GPIO_RegisterCallback(&sw1_pin, sw1_isr, &sw1_pin);
MXC_GPIO_IntConfig(&sw1_pin, MXC_GPIO_INT_FALLING);
MXC_GPIO_EnableInt(sw1_pin.port, sw1_pin.mask);
NVIC_EnableIRQ(MXC_GPIO_GET_IRQ(MXC_GPIO_GET_IDX(sw1_pin.port)));
// 设置输入按钮:P1.7 - SW2
sw2_pin.pad = MXC_GPIO_PAD_PULL_UP;
sw2_pin.func = MXC_GPIO_FUNC_IN;
sw2_pin.vssel = MXC_GPIO_VSSEL_VDDIOH;
MXC_GPIO_Config(&sw2_pin);
//MXC_GPIO_RegisterCallback(&sw2_pin, sw2_isr, &blue_led_pin);
MXC_GPIO_RegisterCallback(&sw2_pin, sw2_isr, &sw2_pin);
MXC_GPIO_IntConfig(&sw2_pin, MXC_GPIO_INT_FALLING);
MXC_GPIO_EnableInt(sw2_pin.port, sw2_pin.mask);
NVIC_EnableIRQ(MXC_GPIO_GET_IRQ(MXC_GPIO_GET_IDX(sw2_pin.port)));
}
int main(void) {
MOTOR_DIR_Type old_motor_dir = -1; // 马达方向, P0.17
MOTOR_RUN_Type oldmotor_run = -1; // 马达启停,
int flagFresh = 0;
MXC_Delay(MXC_DELAY_MSEC(500)); //Wait for PMIC to power-up
MXC_SYS_Clock_Select(MXC_SYS_CLOCK_IPO);
SystemCoreClockUpdate();
// 初始化OLED
printf("\r\nOLED Init");
OLED_init();
OLED_clear();
OLED_ShowString(0, 0, (char *)" EEWORLD & DigiKey", 12, 1);
MXC_Delay(MXC_DELAY_SEC(1));
// 设置输入Key
setInputKey();
// 初始状态:马达不转(不启动定时器3,顺时针转)
tmc2209_Init();
printf("\n Ready! \n");
OLED_Refresh();
while (1) {
MXC_Delay(MXC_DELAY_MSEC(50));
// 动态显示当前步进电机的转向和转动状态
if (old_motor_dir != motor_dir) {
old_motor_dir = motor_dir;
flagFresh = 1;
// 方向:CW-顺时针,CCW-逆时针
if (motor_dir ==Shun ) {
OLED_ShowString(10, 21, (char *)" CW ", 16, 0);
OLED_ShowString(70, 21, (char *)" CCW ", 16, 1);
} else {
OLED_ShowString(10, 21, (char *)" CW ", 16, 1);
OLED_ShowString(70, 21, (char *)" CCW ", 16, 0);
}
}
if (oldmotor_run != motor_run) {
oldmotor_run = motor_run;
flagFresh = 1;
// 转动状态:Stop-停止;Run-转动
if (motor_run ==Stop ) {
OLED_ShowString(10, 40, (char *)" RUN ", 16, 1);
OLED_ShowString(70, 40, (char *)" STOP ", 16, 0);
} else {
OLED_ShowString(10, 40, (char *)" RUN ", 16, 0);
OLED_ShowString(70, 40, (char *)" STOP ", 16, 1);
}
}
if (flagFresh == 1) {
OLED_Refresh();
flagFresh = 0;
}
}
return 0;
}
定时器3负责周期产生PWM脉冲信号,作为TMC2209 的STEP步进脉冲信号。主要代码如下:
// 定时器中断
void Timer3Handler(void) {
MXC_TMR_ClearFlags(Basic_TIMER);
if (motor_run == Run) {
MXC_GPIO_OutToggle(red_led_pin.port, red_led_pin.mask);
MXC_GPIO_OutToggle(motor_step_pin.port, motor_step_pin.mask);
} else {
MXC_GPIO_OutSet(red_led_pin.port, red_led_pin.mask);
//MXC_GPIO_OutClr(motor_step_pin.port, motor_step_pin.mask);
}
}
void Timer3Init(void) {
mxc_tmr_cfg_t tmr;
uint32_t periodTicks = MXC_TMR_GetPeriod(Basic_TIMER, Basic_CLOCK_SOURCE, 128, Basic_FREQ);
MXC_TMR_Shutdown(Basic_TIMER);
MXC_SYS_ClockDisable(MXC_SYS_PERIPH_CLOCK_TMR3);
tmr.pres = TMR_PRES_128;
tmr.mode = TMR_MODE_CONTINUOUS;
tmr.bitMode = TMR_BIT_MODE_16A;
tmr.clock = Basic_CLOCK_SOURCE;
tmr.cmp_cnt = periodTicks; //SystemCoreClock*(1/interval_time);
tmr.pol = 0;
if (MXC_TMR_Init(Basic_TIMER, &tmr, false) != E_NO_ERROR) {
printf("Failed Continuous timer Initialization.\n");
return;
}
MXC_NVIC_SetVector(TMR3_IRQn, Timer3Handler);
NVIC_EnableIRQ(TMR3_IRQn);
MXC_TMR_EnableInt(Basic_TIMER);
printf("Continuous timer started.\n");
MXC_TMR_Start(Basic_TIMER);
}
三、测试效果:
四、总结
定时器处理这一块,一开始我是参照TMR例程做的,遇到各种问题。例程中默认在FTHR_RevA开发板模式下使用的是TIMER4的,设置中断处理时又指向了TIMER5,总之是比较乱,不可用。我就改成了TIMER3。在TIMER3中,tmr.bitMode 不要使用 TMR_BIT_MODE_16B,也会出莫名其妙的问题。

