文章目录
- 1、解除写保护
- 2、极海驱动板资源概述
- 3、新建工程
- 4、点灯
- 5、嘀嗒定时器
- 6、中断
- 7、串口打印
- 8、adc读取
- 9、i2c尝试
- 10、定时器测试
- 11、电机驱动pwm测试
上一篇文章算是简单了解了一下极海的板子开发环境吧,结果前几天板子来了,然后发现一个大bug,板子的芯片居然写保护了,不能刷flash,这里记录一下排查的过程
烧录是这个样子
1、解除写保护
先说一下解决方案吧,目前来看解决方案就是,安装一个jlink,之后打卡这个
这里因为我们是APM32F0,这里对应的选一下F0就行,也就是2
之后打印这个就是OK
下面的一个步骤至关重要,就是不要断电后再用stlink连接,这时候就可以刷固件了
2、极海驱动板资源概述
下面看一下板子的资源,首先是电源电路,稳压出来了12v,5v和3.3v
最小系统这里没什么特别的,就是晶振加复位电路
之后是一些常见的外设,这里关注一下USB引出了一路串口,为串口2,然后是两个按键,一个led
下面是foc的检测电路,电流和霍尔的
foc的驱动芯片用的是FD6288
三相驱动的mos
电流检测电路
3、新建工程
这个参考这个老哥的吧,或者参考我之前的那篇eide的文章,也是可以的,这里因为apm32使用eide不能下代码,后面我就还是用keil了
添加链接描述
我是比较喜欢这种方式的
添加到keil里面这样
bsp里面是自己实现的一些驱动,app里面写一些功能性的东西,最后编译一下(这里直接把demo的程序复制过来就行)
编译通过的话就说明工程没什么问题了
4、点灯
这里我们参考这个样例
我觉得官方的这个样例写的还不错,他所有的外设是统一管理的,用这两个文件来描述外设资源
然后相关的资源都是用的宏来表示,这个和之前看过的野火的stm32教程很像
值得好评的是这里还用了枚举的方式来表示具体的外设资源,值得好评
但是他这个demo的板子的资源和我们的还是不太一样,因此还是不能直接用的,需要一个适合我们自己的,因此这里我结合他的代码风格写了一个适合我们驱动板的,这里直接贴代码
/*!* @file main.h** @brief Header for main.c module** @version V1.0.0** @date 2022-09-30** @attention** Copyright (C) 2022-2023 Geehy Semiconductor** You may not use this file except in compliance with the* GEEHY COPYRIGHT NOTICE (GEEHY SOFTWARE PACKAGE LICENSE).** The program is only for reference, which is distributed in the hope* that it will be useful and instructional for customers to develop* their software. Unless required by applicable law or agreed to in* writing, the program is distributed on an "AS IS" BASIS, WITHOUT* ANY WARRANTY OR CONDITIONS OF ANY KIND, either express or implied.* See the GEEHY SOFTWARE PACKAGE LICENSE for the governing permissions* and limitations under the License.*//* Define to prevent recursive inclusion */
#ifndef __MAIN_H
#define __MAIN_H#ifdef __cplusplus
extern "C" {
#endif/* Includes */
#include "apm32f035.h"#include "apm32f035_gpio.h"
#include "apm32f035_usart.h"
#include "apm32f035_rcm.h"
#include "apm32f035_misc.h"
#include "apm32f035_eint.h"
#include "apm32f035_syscfg.h"
#include "apm32f035_adc.h"#define DEBUG_USART USART2#define LEDn 1
#define LED1_PIN GPIO_PIN_15
#define LED1_GPIO_PORT GPIOC
#define LED1_GPIO_CLK RCM_AHB_PERIPH_GPIOC#define BUTTONn 2#define KEY1_BUTTON_PIN GPIO_PIN_13
#define KEY1_BUTTON_GPIO_PORT GPIOC
#define KEY1_BUTTON_GPIO_CLK RCM_AHB_PERIPH_GPIOC
#define KEY1_BUTTON_EXTI_LINE EINT_LINE13#define KEY2_BUTTON_PIN GPIO_PIN_14
#define KEY2_BUTTON_GPIO_PORT GPIOC
#define KEY2_BUTTON_GPIO_CLK RCM_AHB_PERIPH_GPIOC
#define KEY2_BUTTON_EXTI_LINE EINT_LINE14#define COMn 2#define MINI_COM1 USART1
#define MINI_COM1_CLK RCM_APB2_PERIPH_USART1#define MINI_COM1_TX_PIN GPIO_PIN_9
#define MINI_COM1_TX_GPIO_PORT GPIOA
#define MINI_COM1_TX_GPIO_CLK RCM_AHB_PERIPH_GPIOA
#define MINI_COM1_TX_SOURCE GPIO_PIN_SOURCE_9
#define MINI_COM1_TX_AF GPIO_AF_PIN1#define MINI_COM1_RX_PIN GPIO_PIN_10
#define MINI_COM1_RX_GPIO_PORT GPIOA
#define MINI_COM1_RX_GPIO_CLK RCM_AHB_PERIPH_GPIOA
#define MINI_COM1_RX_SOURCE GPIO_PIN_SOURCE_10
#define MINI_COM1_RX_AF GPIO_AF_PIN1#define MINI_COM1_IRQn USART1_IRQn#define MINI_COM2 USART2
#define MINI_COM2_CLK RCM_APB1_PERIPH_USART2#define MINI_COM2_TX_PIN GPIO_PIN_11
#define MINI_COM2_TX_GPIO_PORT GPIOB
#define MINI_COM2_TX_GPIO_CLK RCM_AHB_PERIPH_GPIOB
#define MINI_COM2_TX_SOURCE GPIO_PIN_SOURCE_11
#define MINI_COM2_TX_AF GPIO_AF_PIN4#define MINI_COM2_RX_PIN GPIO_PIN_12
#define MINI_COM2_RX_GPIO_PORT GPIOB
#define MINI_COM2_RX_GPIO_CLK RCM_AHB_PERIPH_GPIOB
#define MINI_COM2_RX_SOURCE GPIO_PIN_SOURCE_12
#define MINI_COM2_RX_AF GPIO_AF_PIN4#define MINI_COM2_IRQn USART2_IRQntypedef enum {LED1 = 0
} LED_T;typedef enum {BUTTON_KEY1 = 0,BUTTON_KEY2 = 1
} BUTTON_T;typedef enum {BUTTON_MODE_GPIO = 0,BUTTON_MODE_EINT = 1
} BUTTONMODE_T;typedef enum {COM1 = 0,COM2 = 1
} COM_T;#ifdef __cplusplus
}
#endif#endif
新建了一个main.h的文件,结合当前这个驱动板的外设,设计如下
下面开始驱动led,这里关于gpio的驱动我都新建一个文件来管理
前面定义了那些宏,在这里就要用上了,这样就完成了一次封装,很不错
下面是驱动的代码,这里直接贴出来
void GPIO_Init(void)
{GPIO_Config_T gpioConfig;RCM_EnableAHBPeriphClock(LED1_GPIO_CLK);/* LED1 GPIO configuration */gpioConfig.pin = LED1_PIN;gpioConfig.mode = GPIO_MODE_OUT;gpioConfig.outtype = GPIO_OUT_TYPE_PP;gpioConfig.speed = GPIO_SPEED_50MHz;gpioConfig.pupd = GPIO_PUPD_NO;GPIO_Config(LED1_GPIO_PORT, &gpioConfig);
}void APM_MINI_LEDOn(LED_T Led)
{GPIO_PORT[Led]->BR = GPIO_PIN[Led];
}void APM_MINI_LEDOff(LED_T Led)
{GPIO_PORT[Led]->BSC = GPIO_PIN[Led];
}void APM_MINI_LEDToggle(LED_T Led)
{GPIO_PORT[Led]->ODATA ^= GPIO_PIN[Led];
}
5、嘀嗒定时器
这里写法和stm32的那一套基本一致,直接贴,为什么这么写可以参考正点原子的教程
#include "systick.h"uint32_t cntUs = 0;
uint32_t cntMs = 0;void APM_MINI_DelayInit(void)
{SysTick_ConfigCLKSource(SysTick_CLKSource_HCLK_Div8);cntUs = SystemCoreClock / 8000000;cntMs = (uint16_t)cntUs * 1000;
}void APM_MINI_DelayMs(__IO uint32_t nms)
{uint32_t temp;SysTick->LOAD = (uint32_t)nms * cntMs;SysTick->VAL = 0x00;SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;do {temp = SysTick->CTRL;} while ((temp & 0x01) && !(temp & (1 << 16)));SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;SysTick->VAL = 0x00;
}void APM_MINI_DelayUs(__IO uint32_t nus)
{uint32_t temp;SysTick->LOAD = (uint32_t)nus * cntUs;SysTick->VAL = 0x00;SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;do {temp = SysTick->CTRL;} while ((temp & 0x01) && !(temp & (1 << 16)));SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;SysTick->VAL = 0x00;
}
我用逻辑分析仪抓了一下数据,还是比较准的
效果如下:
6、中断
下面看一下gpio的中断部分,首先还是gpio的配置,这里还是普通配置,配置为输入部分,如果要配置中断,可以看到下面加了个中断模式的配置,就需要配置对应的中断。
然后,毫不意外会有一个中断的文件,在这里加入我们的中断服务程序
这个服务函数可以查到是这个
要实现中断服务函数的判断按键状态,也就是下面这个函数
在中断服务程序中判断中断线的状态,之后清除中断标志
效果如下:
7、串口打印
串口也算是基本外设了,这里串口的功能配置如下
直接贴代码
#include "uart.h"
#include "stdio.h"USART_T *COM_USART[COMn] = {MINI_COM1, MINI_COM2};
GPIO_T *COM_TX_PORT[COMn] = {MINI_COM1_TX_GPIO_PORT, MINI_COM2_TX_GPIO_PORT};
GPIO_T *COM_RX_PORT[COMn] = {MINI_COM1_RX_GPIO_PORT, MINI_COM2_RX_GPIO_PORT};
const uint32_t COM_USART_CLK[COMn] = {MINI_COM1_CLK, MINI_COM2_CLK};
const RCM_AHB_PERIPH_T COM_TX_PORT_CLK[COMn] = {MINI_COM1_TX_GPIO_CLK, MINI_COM2_TX_GPIO_CLK};
const RCM_AHB_PERIPH_T COM_RX_PORT_CLK[COMn] = {MINI_COM1_RX_GPIO_CLK, MINI_COM2_RX_GPIO_CLK};
const GPIO_PIN_T COM_TX_PIN[COMn] = {MINI_COM1_TX_PIN, MINI_COM2_TX_PIN};
const GPIO_PIN_T COM_RX_PIN[COMn] = {MINI_COM1_RX_PIN, MINI_COM2_RX_PIN};
const GPIO_PIN_SOURCE_T COM_TX_PIN_SOURCE[COMn] = {MINI_COM1_TX_SOURCE, MINI_COM2_TX_SOURCE};
const GPIO_PIN_SOURCE_T COM_RX_PIN_SOURCE[COMn] = {MINI_COM1_RX_SOURCE, MINI_COM2_RX_SOURCE};
const GPIO_AF_T COM_TX_AF[COMn] = {MINI_COM1_TX_AF, MINI_COM2_TX_AF};
const GPIO_AF_T COM_RX_AF[COMn] = {MINI_COM1_RX_AF, MINI_COM2_RX_AF};void APM_MINI_COMInit(COM_T COM)
{GPIO_Config_T gpioConfig;USART_Config_T usartConfigStruct;/* Enable GPIO clock */RCM_EnableAHBPeriphClock(COM_TX_PORT_CLK[COM] | COM_RX_PORT_CLK[COM]);/* Enable COM1 or COM2 clock */if (COM == COM1) {RCM_EnableAPB2PeriphClock(COM_USART_CLK[COM]);} else {RCM_EnableAPB1PeriphClock(COM_USART_CLK[COM]);}/* Connect PXx to USARTx_Tx */GPIO_ConfigPinAF(COM_TX_PORT[COM], COM_TX_PIN_SOURCE[COM], COM_TX_AF[COM]);/* Connect PXx to USARTx_Rx */GPIO_ConfigPinAF(COM_RX_PORT[COM], COM_RX_PIN_SOURCE[COM], COM_RX_AF[COM]);/* Configure USART Tx as alternate function push-pull */gpioConfig.mode = GPIO_MODE_AF;gpioConfig.pin = COM_TX_PIN[COM];gpioConfig.speed = GPIO_SPEED_50MHz;gpioConfig.outtype = GPIO_OUT_TYPE_PP;gpioConfig.pupd = GPIO_PUPD_PU;GPIO_Config(COM_TX_PORT[COM], &gpioConfig);/* Configure USART Rx as input floating */gpioConfig.pin = COM_RX_PIN[COM];GPIO_Config(COM_RX_PORT[COM], &gpioConfig);/* MINI_USARTs configured as follow:- BaudRate = 115200 baud- Word Length = 8 Bits- One Stop Bit- No parity- Hardware flow control disabled (RTS and CTS signals)- Receive and transmit enabled*/usartConfigStruct.baudRate = 115200;usartConfigStruct.mode = USART_MODE_TX_RX;usartConfigStruct.hardwareFlowCtrl = USART_FLOW_CTRL_NONE;usartConfigStruct.parity = USART_PARITY_NONE;usartConfigStruct.stopBits = USART_STOP_BIT_1;usartConfigStruct.wordLength = USART_WORD_LEN_8B;USART_Config(COM_USART[COM], &usartConfigStruct);/* Enable USART_Interrupt_RXBNEIE */USART_EnableInterrupt(COM_USART[COM], USART_INT_RXBNEIE);if (COM_USART[COM] == USART1) {NVIC_EnableIRQRequest(USART1_IRQn, 2);} else if (COM_USART[COM] == USART2) {NVIC_EnableIRQRequest(USART2_IRQn, 3);}/* Enable USART */USART_Enable(COM_USART[COM]);
}#if defined(__CC_ARM) || defined(__ICCARM__) || (defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050))int fputc(int ch, FILE *f)
{/* send a byte of data to the serial port */USART_TxData(DEBUG_USART, (uint8_t)ch);/* wait for the data to be send */while (USART_ReadStatusFlag(DEBUG_USART, USART_FLAG_TXBE) == RESET);return (ch);
}#elif defined(__GNUC__)
int __io_putchar(int ch)
{/* send a byte of data to the serial port */USART_TxData(DEBUG_USART, ch);/* wait for the data to be send */while (USART_ReadStatusFlag(DEBUG_USART, USART_FLAG_TXBE) == RESET);return ch;
}
int _write(int file, char *ptr, int len)
{int i;for (i = 0; i < len; i++) {__io_putchar(*ptr++);}return len;
}#else
#warning Not supported compiler type
#endif
测试串口输出
8、adc读取
这里adc用这个进行测试,原理图如下,可以看到时PA7引脚,然后连了这两个一个旋转编码器
这里直接贴上adc的配置程序
void ADC_Init(void)
{GPIO_Config_T gpioConfig;ADC_Config_T adcConfig;/* RCM Enable*/RCM_EnableAHBPeriphClock(RCM_AHB_PERIPH_GPIOA);RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_ADC);RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_SYSCFG);/* GPIO Configuration */gpioConfig.pin = GPIO_PIN_7;gpioConfig.mode = GPIO_MODE_AN;gpioConfig.pupd = GPIO_PUPD_PU;GPIO_Config(GPIOA, &gpioConfig);/* ADC Configuration */ADC_Reset();ADC_ConfigStructInit(&adcConfig);/* Set resolution*/adcConfig.resolution = ADC_RESOLUTION_12B;/* Set dataAlign*/adcConfig.dataAlign = ADC_DATA_ALIGN_RIGHT;/* Set scanDir*/adcConfig.scanDir = ADC_SCAN_DIR_UPWARD;/* Set convMode continous*/adcConfig.convMode = ADC_CONVERSION_CONTINUOUS;/* Set extTrigConv*/adcConfig.extTrigConv1 = ADC_EXT_TRIG_CONV_TRG0;/* Set TrigEdge*/adcConfig.extTrigEdge1 = ADC_EXT_TRIG_EDGE_NONE;ADC_Config(&adcConfig);ADC_ConfigChannel(ADC_CHANNEL_7, ADC_SAMPLE_TIME_239_5);/* Enable Interrupt*/ADC_EnableInterrupt(ADC_INT_CS);NVIC_EnableIRQRequest(ADC_COMP_IRQn, 2);/* Calibration*/ADC_ReadCalibrationFactor();/* Enable ADC*/ADC_Enable();
}
上面设置了中断读取,因此我们还需要写一个中断服务程序
void ADC_Isr(void)
{uint32_t adcData = 0;uint32_t voltage = 0;if (ADC_ReadIntFlag(ADC_INT_FLAG_CS) == SET){ADC_ClearIntFlag(ADC_INT_FLAG_CS);/* Read ADC Conversion value */adcData = ADC_ReadConversionValue();/* voltage(mV) = adcData * (3300mV / 4095) */voltage = (adcData * 3300) / 4095;/* output to serial port */printf("voltage : %d mV\r\n", voltage);APM_MINI_LEDToggle(LED1);APM_MINI_DelayMs(1000);}
}
运行结果如下:
9、i2c尝试
这里简单做个oled的实验,没有单片机引脚引出了,因此这里用这个串口的来试试
这里直接贴代码
#include "oled_soft.h"
#include "Font.h"
#include "systick.h"/*
SDA=PD2; //master out slave in
SCL=PC12; //总线时钟
*/
#define OLED_IIC_SDA_APB_GPIO RCM_AHB_PERIPH_GPIOB
#define OLED_IIC_SDA_Pin GPIO_PIN_11
#define OLED_IIC_SDA_GPIO GPIOB#define OLED_IIC_SCL_APB_GPIO RCM_AHB_PERIPH_GPIOB
#define OLED_IIC_SCL_Pin GPIO_PIN_12
#define OLED_IIC_SCL_GPIO GPIOB#define OLED_IIC_SDA_HIGH() GPIO_SetBit(OLED_IIC_SDA_GPIO,OLED_IIC_SDA_Pin) //SDA置位
#define OLED_IIC_SDA_LOW() GPIO_ClearBit(OLED_IIC_SDA_GPIO,OLED_IIC_SDA_Pin) //SDA清0#define OLED_IIC_SCL_HIGH() GPIO_SetBit(OLED_IIC_SCL_GPIO,OLED_IIC_SCL_Pin) //SCL置位
#define OLED_IIC_SCL_LOW() GPIO_ClearBit(OLED_IIC_SCL_GPIO,OLED_IIC_SCL_Pin) //SCL清0void OLED_IIC_SCL(unsigned char sta)
{if (sta) {OLED_IIC_SCL_HIGH();} else {OLED_IIC_SCL_LOW();}// APM_MINI_DelayMs(1);//按照需要添加延时
}
void OLED_IIC_SDA(unsigned char sta)
{if (sta) {OLED_IIC_SDA_HIGH();} else {OLED_IIC_SDA_LOW();}// APM_MINI_DelayMs(1);//按照需要添加延时
}void OLED12864_IoInit(void)//IO初始化
{GPIO_Config_T GPIO_InitStructure; //定义GPIO结构体RCM_EnableAPB2PeriphClock(OLED_IIC_SDA_APB_GPIO); //开启GPIO模块的APB时钟RCM_EnableAPB2PeriphClock(OLED_IIC_SCL_APB_GPIO); //开启GPIO模块的APB时钟GPIO_InitStructure.pin = OLED_IIC_SDA_Pin; //配置端口GPIO_InitStructure.mode = GPIO_MODE_OUT; //配置端口为开漏输出模式GPIO_InitStructure.outtype = GPIO_OUT_TYPE_OD;GPIO_InitStructure.speed = GPIO_SPEED_50MHz; //配置端口速度GPIO_Config(OLED_IIC_SDA_GPIO, &GPIO_InitStructure); //对配置初始化GPIO_InitStructure.pin = OLED_IIC_SCL_Pin; //配置端口GPIO_InitStructure.mode = GPIO_MODE_OUT; //配置端口为开漏输出模式GPIO_InitStructure.outtype = GPIO_OUT_TYPE_OD;GPIO_InitStructure.speed = GPIO_SPEED_50MHz; //配置端口速度GPIO_Config(OLED_IIC_SCL_GPIO, &GPIO_InitStructure); //对配置初始化
}
unsigned char OLED_IIC_SDA_Read(void) //读取SDA
{return GPIO_ReadInputBit(OLED_IIC_SDA_GPIO, OLED_IIC_SDA_Pin);
}
void OLED_IIC_Start(void)//IIC start
{OLED_IIC_SCL(1); //SCL 1 释放SCLOLED_IIC_SDA(1); //SDA 1OLED_IIC_SDA(0); //SDA 0OLED_IIC_SCL(0);
}
void OLED_IIC_Stop(void)//IIC stop
{OLED_IIC_SCL(1); //SCL 1OLED_IIC_SDA(0); //SDA 0OLED_IIC_SDA(1); //SDA 1
}
void OLED_IIC_SendByte(unsigned char dat)
{unsigned char i, temp, Even;temp = dat;for (i = 0; i < 8; i++) {Even = temp & 0x80;temp = temp << 1;if (Even == 0x80) { //先写入高位OLED_IIC_SDA(1);} else {OLED_IIC_SDA(0);}OLED_IIC_SCL(1);OLED_IIC_SCL(0);}
}
void OLED_IIC_SendACK(unsigned char dat)//主机产生应答
{OLED_IIC_SDA(dat);OLED_IIC_SCL(1);OLED_IIC_SCL(0);
}
unsigned char OLED_IIC_ReceByte(void)
{unsigned char i, temp = 0;OLED_IIC_SDA(1);//释放SDA 有SCL接管for (i = 0; i < 8; i++) {OLED_IIC_SCL(1);if (OLED_IIC_SDA_Read()) {temp = temp | 0x01;}temp = temp << 1;OLED_IIC_SCL(0);}return temp;
}
unsigned char OLED_IIC_ReceACK(void)//丛机产生应答 由主机读取
{unsigned char AckBit = 0x00;OLED_IIC_SDA(1);//释放SDAOLED_IIC_SCL(1);AckBit = OLED_IIC_SDA_Read();OLED_IIC_SCL(0);return AckBit;
}
void OLED12864_SendCom(unsigned char cmd)
{OLED_IIC_Start();OLED_IIC_SendByte(0x78); //器件地址0x78 读写位0 写入OLED_IIC_ReceACK();OLED_IIC_SendByte(0x00); //命令关键字OLED_IIC_ReceACK();OLED_IIC_SendByte(cmd); //写入的命令OLED_IIC_ReceACK();OLED_IIC_Stop();
}
void OLED12864_SendData(unsigned char dat)
{OLED_IIC_Start();OLED_IIC_SendByte(0x78); //器件地址0x78 读写位0 写入OLED_IIC_ReceACK();OLED_IIC_SendByte(0x40); //数据寄存器地址OLED_IIC_ReceACK();OLED_IIC_SendByte(dat); //写入的数据OLED_IIC_ReceACK();OLED_IIC_Stop();
}
unsigned char OLED12864_ReadData(unsigned char Add)
{unsigned char temp = 0;OLED_IIC_Start();OLED_IIC_SendByte(0x78); //器件地址0x78 读写位0 写入OLED_IIC_ReceACK();OLED_IIC_SendByte(Add); //数据寄存器地址OLED_IIC_ReceACK();OLED_IIC_Start();OLED_IIC_SendByte(0x78 | 0x01); //器件地址0x78 读写位1 读出OLED_IIC_ReceACK();temp = OLED_IIC_ReceByte();OLED_IIC_SendACK(1);OLED_IIC_Stop();return temp;
}void OLED12864_Init(void)
{OLED12864_IoInit(); //IO闁告帗绻傞~鎰板礌閿燂拷APM_MINI_DelayMs(20);OLED12864_SendCom(0xAE);//命令AE:关闭OLED面板 AF:ONOLED12864_SendCom(0x02);//---set low column addressOLED12864_SendCom(0x10);//---set high column addressOLED12864_SendCom(0x40);//--set start line address Set Mapping RAM Display Start Line (0x00~0x3F)OLED12864_SendCom(0x81);//--set contrast control registerOLED12864_SendCom(0xCF); // Set SEG Output Current BrightnessOLED12864_SendCom(0xA1);//0xa0左右反置 0xa1正常OLED12864_SendCom(0xC8);//0xc0上下反置 0xc8正常OLED12864_SendCom(0xA6);//--set normal displayOLED12864_SendCom(0xA8);//--set multiplex ratio(1 to 64)OLED12864_SendCom(0x3f);//--1/64 dutyOLED12864_SendCom(0x81);//对比度设置OLED12864_SendCom(0xFF);//1~255;默认0X7F (亮度设置,越大越亮)OLED12864_SendCom(0xD3);//-set display offset Shift Mapping RAM Counter (0x00~0x3F)OLED12864_SendCom(0x00);//-not offsetOLED12864_SendCom(0xd5);//--set display clock divide ratio/oscillator frequencyOLED12864_SendCom(0x80);//--set divide ratio, Set Clock as 100 Frames/SecOLED12864_SendCom(0xD9);//--set pre-charge periodOLED12864_SendCom(0xF1);//Set Pre-Charge as 15 Clocks & Discharge as 1 ClockOLED12864_SendCom(0xDA);//--set com pins hardware configurationOLED12864_SendCom(0x12);OLED12864_SendCom(0xDB);//--set vcomhOLED12864_SendCom(0x40);//Set VCOM Deselect LevelOLED12864_SendCom(0x20);//-Set Page Addressing Mode (0x00/0x01/0x02)OLED12864_SendCom(0x02);//OLED12864_SendCom(0x8D);//--set Charge Pump enable/disableOLED12864_SendCom(0x14);//--set(0x10) disableOLED12864_SendCom(0xA4);// Disable Entire Display On (0xa4/0xa5)OLED12864_SendCom(0xA6);// Disable Inverse Display On (0xa6/a7)OLED12864_SendCom(0xAF);//--turn on oled panelOLED12864_Clean(); //
}Point Buff;
Point Start;unsigned char DisBuff[8][128] = {0}; //用于显示的缓存
/*********将光标指向坐标(x,y)*********************
** 功能: 将光标指向坐标(x,y)
** 参数: X:y:坐标 x 0-127 ,y 0-7
** 返回值:无
******************************************************/
void Location(unsigned char x, unsigned char y)
{OLED12864_SendCom(0xb0 + y); //设置页OLED12864_SendCom(0x10 + ((x >> 4) & 0x0f)); //设置列高4位OLED12864_SendCom(x & 0x0f); //设置列低4位
}
/*********OLED对比度调节************************************
** 功能:OLED对比度调节
** 参数: vlcd:微调对比度数值 Vlcd:0x00~0xff 中间值:0x7f
** 返回值:无
******************************************************/
void OLED12864_TurnBias(unsigned char Vlcd)
{OLED12864_SendCom(0x81); //微调对比度命令OLED12864_SendCom(Vlcd); //微调对比度的值,要与命令0x81一起使用 可设置范围 0x00~0xff
}
/*********设置缓冲区指针坐标*********************
** 功能: 设置缓冲区指针坐标
** 参数: x:0~127 y:0~63
** 返回值:无
******************************************************/
void OLED12864_Location(unsigned char x, unsigned char y)
{if (y >= LCD_Y) {y = 0; //纠正错误纵坐标输入}if (x >= LCD_X) {x = 0; //纠正错误横坐标输入}Buff.y = y; //设置纵坐标Buff.x = x; //设置横坐标
}
/*********将整个缓冲区全部写入液晶*********************
** 功能: 将整个缓冲区全部写入液晶 即显示整个DisBuff的内容 调试用
** 参数: 无
** 返回值:无
******************************************************/
void RefreshAll(void)
{unsigned char i, j;Location(0, 0);for (i = 0; i < LCD_COLUMN; i++) {for (j = 0; j < LCD_X; j++) {Location(j, i);OLED12864_SendData(DisBuff[i][j]);}}
}
/*********将指定缓冲区指定区域写入*********************
** 功能: 将整个缓冲区指定区域写入
** 参数: x:0-127 y:0-63 Width:0-127:长度 Height:0-63:高度
** 返回值:无
******************************************************/
void Refresh(unsigned char x, unsigned char y, unsigned char Width, unsigned char Height)
{unsigned char WidthI, HeightI;unsigned char StartRow, StartColumn, EndRow, EndColumn;StartRow = y / 8; //刷新起始行StartColumn = x; //刷新起始列EndRow = (y + Height - 1) / 8; //刷新终止行EndColumn = x + Width - 1;//刷新终止列for (HeightI = StartRow; HeightI <= EndRow; HeightI++) { //刷新第height_i行 //刷新指定行Location(StartColumn, HeightI); //刷新该行的width列 //从行首开始刷新for (WidthI = StartColumn; WidthI <= EndColumn; WidthI++) { //刷新每行的指定列OLED12864_SendData(DisBuff[HeightI][WidthI]);}}
}
/*********清除缓冲区1字节数据*********************
** 功能: 清除缓冲区1字节数据,x,y为该字节最低位起始坐标
** 参数: x:0-127 y:0-63
** 返回值:无
比如 ClearPointofBuf(15,25); 即清除当前点所在字节的坐标点 即清除点:
(15,25)(15,26)(15,27)(15,28)(15,29)(15,30)(15,31)(15,32)
******************************************************/
void ClearPointofBuf(unsigned char x, unsigned char y)
{unsigned char Column, ColumnBit;OLED12864_Location(x, y);Column = Buff.y / 8; //要清除的缓冲区的字节行坐标ColumnBit = Buff.y % 8; //坐标在该字节8bit的bit位置DisBuff[Column][Buff.x] &= ~(0x01 << (ColumnBit)); //清除指向的缓冲区字节//if(ColumnBit)//DisBuff[Column+1][Buff.x]&=~(0xff>>(8-ColumnBit));//字节跨两行就清除下一行
}
/*********写一个字节数据到缓冲区*********************
** 功能: 写一个字节数据到缓冲区,写入字节后x会自加
** 参数: byte:要写入的字节
** 返回值:无
******************************************************/
void WriteBytetoBuf(unsigned char byte)
{unsigned char Column, ColumnBit;Column = Buff.y / 8; //要写的缓冲区的字节行坐标ColumnBit = Buff.y % 8; //坐标在该字节8bit的bit位置DisBuff[Column][Buff.x] |= byte << (ColumnBit); //将1字节数据写入DisBuff指向的缓冲区字节if (ColumnBit) {DisBuff[Column + 1][Buff.x] |= byte >> (8 - ColumnBit); //字节跨两行就写下一行}if (Buff.x >= LCD_X) { //到达行尾缓冲区指针自动跳转到下一行行首Buff.x = 0;Buff.y += 8;if (Buff.y >= LCD_Y) { //到达页面末尾,缓冲区指针跳到页面开头Buff.y = 0;}} else {Buff.x++; //缓冲区指针指向下一列}
}void WriteRevBytetoBuf(unsigned char byte)
{unsigned char Column, ColumnBit, temp;Column = Buff.y / 8; //要写的缓冲区的字节行坐标ColumnBit = Buff.y % 8;temp = byte << (ColumnBit);temp = ~temp;temp = temp >> (ColumnBit); //坐标在该字节8bit的bit位置temp = temp << (ColumnBit);DisBuff[Column][Buff.x] |= temp; //将1字节数据写入DisBuff指向的缓冲区字节if (ColumnBit) {temp = byte >> (8 - ColumnBit);temp = ~temp;temp = temp << (8 - ColumnBit);temp = temp >> (8 - ColumnBit);DisBuff[Column + 1][Buff.x] |= temp;}//字节跨两行就写下一行if (Buff.x >= LCD_X) { //到达行尾缓冲区指针自动跳转到下一行行首Buff.x = 0;Buff.y += 8;if (Buff.y >= LCD_Y) { //到达页面末尾,缓冲区指针跳到页面开头Buff.y = 0;}} else {Buff.x++; //缓冲区指针指向下一列}
}
/*********清空整个缓冲区*********************
** 功能: 清空整个缓冲区
** 参数: 无
** 返回值:无
******************************************************/
void ClearAllBuf(void)
{unsigned char i, j;for (j = 0; j < LCD_COLUMN; j++) {for (i = 0; i < LCD_ROW; i++) {DisBuff[j][i] = 0x00; //写0到缓冲区以清除该字节数据}}
}
/*********清空整个缓冲区并将缓冲区中数据全部写入*********************
** 功能: 清空整个缓冲区并送入数据
** 参数: 无
** 返回值:无
******************************************************/
void OLED12864_Clean(void)
{ClearAllBuf(); //清除缓冲区RefreshAll(); //刷新 送入数据
}
/*********清空缓冲区指定区域*********************
** 功能: 清空缓冲区指定区域
** 参数: x:0-127 y:0-63 Width:0-127 Height:0-63
** 返回值:无
******************************************************/
void ClearBuf(unsigned char x, unsigned char y, unsigned char Width, unsigned char Height)
{unsigned char i, j;Height = y + Height; //获得刷新的终止纵坐标Width = Width + x; //获得刷新的终止横坐标for (j = y; j < Height; j++) {for (i = x; i < Width; i++) {ClearPointofBuf(i, j); //写0到缓冲区以清除该点}}
}
/*********清空指定区域*********************
** 功能: 清空指定区域
** 参数: x:0-127 y:0-63 Width:0-127 Height:0-63
** 返回值:无
******************************************************/
void ClearArea(unsigned char x, unsigned char y, unsigned char Width, unsigned char Height)
{ClearBuf(x, y, Width, Height);Refresh(x, y, Width, Height); //刷新 指定区域
}高度为8的字符显示函数//
/*********写一个(6*8)字符到缓冲区(不需要坐标,紧跟上个字符)*********************
** 功能: 写一个(6*8)字符到缓冲区
** 参数: value:字符
** 返回值:无
******************************************************/
void WriteChartoBuf(unsigned char value)
{unsigned char i;for (i = 0; i < 6; i++) { //连续写六个字节WriteBytetoBuf(Font6x8[value - 0x20][i]);}
}
/*********写一个反白(6*8)*********************
** 功能: 写一个反白(6*8)字符到缓冲区
** 参数: value:字符
** 返回值:无
******************************************************/
void WriteRevChartoBuf(unsigned char value)
{unsigned char i;for (i = 0; i < 6; i++) { //连续写六个字节WriteBytetoBuf(~Font6x8[value - 0x20][i]);}
}
/*********通过缓冲区写一个ASCII字符(6*8)并刷新(不需要坐标,紧跟上个字符)*********************
** 功能: 通过缓冲区写一个ASCII字符(6*8)并刷新
** 参数: value:字符
** 返回值:无
******************************************************/
void OLED12864_DisChar(unsigned char x, unsigned char y, unsigned char value)
{OLED12864_Location(x, y);Start.x = Buff.x; //获得开始横坐标Start.y = Buff.y; //获得开始纵坐标WriteChartoBuf(value);Refresh(Start.x, Start.y, 6, 8); //刷新 指定区域
}
/*********刷新显示一个独立的字符*********************
** 功能: 刷新显示一个独立的字符
** 参数: value:字符
** 返回值:无
******************************************************/
void OLED12864_DisOneChar(unsigned char x, unsigned char y, bit Rev, unsigned char value)
{OLED12864_Location(x, y);Start.x = Buff.x; //获得开始横坐标Start.y = Buff.y; //获得开始纵坐标ClearBuf(Start.x, Start.y, 6, 8);OLED12864_Location(x, y);if (Rev) {WriteRevChartoBuf(value);} else {WriteChartoBuf(value);}Refresh(Start.x, Start.y, 6, 8); //刷新 指定区域
}/*********写一个字符串(高度8)到缓冲区(不需要坐标,紧跟上个字符)*********************
** 功能: 写一个字符串(高度8)到缓冲区
** 参数: *str:字符串 注意:字符串长度不能超过22
** 返回值:字符串长度
******************************************************/
unsigned char WriteStrtoBuf(char *str)
{unsigned char str_len = 0;while (*str != '\0') {WriteChartoBuf(*str++);str_len++;}return str_len; //返回字符串长度
}
/*********写一个反白字符串(高度8)到缓冲区(不需要坐标,紧跟上个字符)*********************
** 功能: 写一个反白字符串(高度8)到缓冲区
** 参数: *str:字符串
** 返回值:字符串长度
******************************************************/
unsigned char WriteRevStrtoBuf(char *str)
{unsigned char str_len = 0;while (*str != '\0') {WriteRevChartoBuf(*str++);str_len++;}return str_len; //返回字符串长度
}/*********写一个字符串(高度8)到缓冲区并刷新(不需要坐标,紧跟上个字符)*********************
** 功能: 写一个字符串(高度8)到缓冲区并刷新注意刷新范围为字符串所在的行 字符串显示不超过一行 对于128*64 最多不超过21个字符
** 参数: x:0-127 横坐标y:0-63 纵坐标Rev:0:正常显示 1:反白显示*str:字符串
** 返回值:字符串长度
******************************************************/
unsigned char OLED12864_DisStr(unsigned char x, unsigned char y, bit Rev, char *str)
{unsigned char Width, Height, str_len;OLED12864_Location(x, y);Start.x = Buff.x; //获得开始横坐标Start.y = Buff.y; //获得开始纵坐标if (Rev) {str_len = WriteRevStrtoBuf(str);} else {str_len = WriteStrtoBuf(str);}Height = 8; //获得刷新高度Width = str_len * 6;; //获得字符串起始纵坐标Refresh(Start.x, Start.y, Width, Height); //刷新显示区域return str_len; //返回字符串长度
}
/*********显示反白字符串*********************
** 功能: 显示反白字符串注意刷新范围为字符串所在的行 字符串显示不超过一行
** 参数: *str:字符串
** 返回值:字符串长度
******************************************************/
unsigned char OLED12864_DisRevStr(char *str)
{unsigned char Width, Height, str_len;Start.x = Buff.x; //获得开始横坐标Start.y = Buff.y; //获得开始纵坐标str_len = WriteRevStrtoBuf(str);Height = 8; //获得刷新高度Width = str_len * 6;; //获得字符串起始纵坐标Refresh(Start.x, Start.y, Width, Height); //刷新显示区域return str_len; //返回字符串长度
}
/*-------将一个数字转化为字符串并6*8显示------------------------------------------------
** 功能:将一个数字转化为字符串并显示如果要改变显示格式 就要改变sprintf函数的命令格式符如果要改变显示长度 就要改变str[]数组的长度
** 参数: temp:要显示的变量** 返回值:无
-----------------------------------------------------------------------*/
void OLED12864_Format1(unsigned char x, unsigned char y, bit Rev, unsigned int temp)
{char str[5];unsigned char L;//sprintf(str,"%d",temp); //产生“123″L = sprintf(str, "%04d", temp); //产生“0123″ClearBuf(x, y, L * 6, 8);OLED12864_DisStr(x, y, Rev, str);
}
void OLED12864_Format2(unsigned char x, unsigned char y, bit Rev, unsigned int temp)
{char str[5];unsigned char L;L = sprintf(str, "%02x", temp); //产生“01″ClearBuf(x, y, L * 6, 8);OLED12864_DisStr(x, y, Rev, str);
}
void OLED12864_Format3(unsigned char x, unsigned char y, bit Rev, unsigned int temp)
{char str[4];unsigned char L;//sprintf(str,"%d",temp); //产生“123″L = sprintf(str, "%02d", temp); //产生“001″ClearBuf(x, y, L * 6, 8);OLED12864_DisStr(x, y, Rev, str);
}
void OLED12864_Format4(unsigned char x, unsigned char y, bit Rev, unsigned int temp)
{char str[10];unsigned char L;//sprintf(str,"%d",temp); //产生“123″L = sprintf(str, "%04dmA", temp); //产生“1.22A″ClearBuf(x, y, L * 6, 8);OLED12864_DisStr(x, y, Rev, str);
}
void OLED12864_Format5(unsigned char x, unsigned char y, bit Rev, float temp)
{char str[10];unsigned char L;//sprintf(str,"%d",temp); //产生“123″L = sprintf(str, "%4.2fV", temp); //产生“1.22V″ClearBuf(x, y, L * 6, 8);OLED12864_DisStr(x, y, Rev, str);
}
void OLED12864_Format6(unsigned char x, unsigned char y, bit Rev, unsigned int temp)
{char str[5];unsigned char L;//sprintf(str,"%d",temp); //产生“123″L = sprintf(str, "%03d", temp); //产生“0123″ClearBuf(x, y, L * 6, 8);OLED12864_DisStr(x, y, Rev, str);
}
高度为12的字符显示函数///
/*-------写一个ASCII字符(8*12)到缓冲区------------------------------------------------
** 功能:写一个ASCII字符(8*12)到缓冲区
** 参数: value:要显示的数字ASCII
** 返回值:无
-----------------------------------------------------------------------*/
void WriteBigChar(unsigned char value)
{unsigned char i;for (i = 0; i < 8; i++) { //写上面一行WriteBytetoBuf(Font8x12[value - 0x20][i]);}Buff.x = Buff.x - 8; //写下面一行Buff.y = Buff.y + 8;for (i = 8; i < 16; i++) {WriteBytetoBuf(Font8x12[value - 0x20][i]);}
}
/*-------写一个反白ASCII字符(8*12)到缓冲区------------------------------------------------
** 功能:写一个反白ASCII字符(8*12)到缓冲区
** 参数: value:要显示的数字ASCII
** 返回值:无
-----------------------------------------------------------------------*/
void WriteBigRevChar(unsigned char value)
{unsigned char i;for (i = 0; i < 8; i++) { //写上面一行WriteBytetoBuf(~Font8x12[value - 0x20][i]);}Buff.x = Buff.x - 8; //写下面一行Buff.y = Buff.y + 8;for (i = 8; i < 16; i++) {WriteBytetoBuf((~(Font8x12[value - 0x20][i] << 4)) >> 4); //只反白低4位}
}/*********显示一个8*12字符*********************
** 功能: 刷新显示一个8*12字符串
** 参数: value:字符ASCIi Rev:是否反白
** 返回值:无
******************************************************/
void OLED12864_DisBigChar(unsigned char value, bit Rev)
{Start.x = Buff.x; //获得开始横坐标Start.y = Buff.y; //获得开始纵坐标if (Rev) {WriteBigRevChar(value);} else {WriteBigChar(value);}Refresh(Start.x, Start.y, 8, 12); //刷新 指定区域
}/*********写一个8*12字符串到缓冲区*********************
** 功能: 写一个8*12字符串到缓冲区 ,每行最多显示128/8个字符
** 参数: *str:字符串 Rev:1:反白 0:不反白
** 返回值:字符串长度
******************************************************/
unsigned char WriteBigStr(char *str, bit Rev)
{unsigned char str_len = 0;while (*str != '\0') {if (Rev) {WriteBigRevChar(*str++);} else {WriteBigChar(*str++);}Buff.y = Buff.y - 8;str_len++;}return str_len; //返回字符串长度
}
void Write6BigStr(char *str, bit Rev)
{unsigned char i = 0;for (i = 0; i < 6; i++) {if (Rev) {WriteBigRevChar(*str++);} else {WriteBigChar(*str++);}Buff.y = Buff.y - 8;}
} //返回字符串长度/*********刷新显示一个独立8*12的字符*********************
** 功能: 刷新显示一个独立的字符
** 参数: value:字符
** 返回值:无
******************************************************/
void OLED12864_DisOneBigChar(unsigned char x, unsigned char y, bit Rev, unsigned char value)
{OLED12864_Location(x, y);Start.x = Buff.x; //获得开始横坐标Start.y = Buff.y; //获得开始纵坐标ClearBuf(Start.x, Start.y, 8, 12);OLED12864_Location(x, y);if (Rev) {WriteBigRevChar(value);} else {WriteBigChar(value);}Refresh(Start.x, Start.y, 8, 12); //刷新 指定区域
}
/*********写一个字符串(高度12)到缓冲区并刷新(不需要坐标,紧跟上个字符)*********************
** 功能: 写一个字符串(高度12)到缓冲区并刷新注意刷新范围为字符串所在的行 字符串显示不超过一行 对于128*64 最多不超过21个字符
** 参数: x:0-127 横坐标y:0-63 纵坐标Rev:0:正常显示 1:反白显示*str:字符串
** 返回值:字符串长度
******************************************************/
unsigned char OLED12864_DisBigStr(unsigned char x, unsigned char y, bit Rev, char *str)
{unsigned char Width, Height, str_len;OLED12864_Location(x, y);Start.x = Buff.x; //获得开始横坐标Start.y = Buff.y;if (Rev) { //获得开始纵坐标str_len = WriteBigStr(str, 1);} else {str_len = WriteBigStr(str, 0);}Height = 12; //获得刷新高度Width = str_len * 8;; //获得字符串起始纵坐标Refresh(Start.x, Start.y, Width, Height); //刷新显示区域return str_len; //返回字符串长度
}void OLED12864_DisBigStr1(unsigned char x, unsigned char y, bit Rev, char *str)
{unsigned char Width, Height;OLED12864_Location(x, y);Start.x = Buff.x; //获得开始横坐标Start.y = Buff.y;if (Rev) { //获得开始纵坐标Write6BigStr(str, 1);} else {Write6BigStr(str, 0);}Height = 12; //获得刷新高度Width = 6 * 8;; //获得字符串起始纵坐标Refresh(Start.x, Start.y, Width, Height); //刷新显示区域 //返回字符串长度
}
/*-------将一个变量转化为字符串并8*12显示------------------------------------------------
** 功能:将一个数字转化为字符串并显示如果要改变显示格式 就要改变sprintf函数的命令格式符如果要改变显示长度 就要改变str[]数组的长度
** 参数: temp:要显示的变量** 返回值:无
-----------------------------------------------------------------------*/
void OLED12864_BigFormat1(unsigned char x, unsigned char y, bit Rev, unsigned int temp)
{char str[5];unsigned char L;//L=sprintf(str,"%d",temp); //产生“1″L = sprintf(str, "%04d", temp); //产生“0123″ClearBuf(x, y, L * 8, 12);OLED12864_DisBigStr(x, y, Rev, str);
}
void OLED12864_BigFormat2(unsigned char x, unsigned char y, bit Rev, unsigned int temp)
{char str[5];unsigned char L;//L=sprintf(str,"%d",temp); //产生“1″L = sprintf(str, "%02d", temp); //产生“01″ClearBuf(x, y, L * 8, 12);OLED12864_DisBigStr(x, y, Rev, str);
}
void OLED12864_BigFormat3(unsigned char x, unsigned char y, bit Rev, float temp)
{char str[7];unsigned char L;//L=sprintf(str,"%d",temp); //产生“1″L = sprintf(str, "%04.1f", temp); //产生“01.00v″ClearBuf(x, y, L * 8, 12);OLED12864_DisBigStr(x, y, Rev, str);
}
void OLED12864_BigFormat4(unsigned char x, unsigned char y, bit Rev, float temp)
{char str[10];unsigned char L;//L=sprintf(str,"%d",temp); //产生“1″L = sprintf(str, "%4.2fV", temp); //产生“01.1V″ClearBuf(x, y, L * 8, 12);OLED12864_DisBigStr(x, y, Rev, str);
}
void OLED12864_BigFormat5(unsigned char x, unsigned char y, bit Rev, unsigned int temp)
{char str[10];unsigned char L;//L=sprintf(str,"%d",temp); //产生“1″L = sprintf(str, "%3d%", temp); //产生“100%″ClearBuf(x, y, L * 8, 12);OLED12864_DisBigStr(x, y, Rev, str);
}
/*********写一个12X12汉字到缓冲区*********************
** 功能: 写一个12X12汉字符到缓冲区
** 参数: x:0-127 y:0-63 Hanzi[]:存放汉字数组 单行24个数值 Rev:反白 1:反白 0:正常显示
** 返回值:无
******************************************************/
void WriteBigCh(unsigned char x, unsigned char y, const unsigned char Hanzi[], bit Rev)
{unsigned char i;OLED12864_Location(x, y); //写上面一行for (i = 0; i < 12; i ++) {if (Rev) {WriteBytetoBuf(~Hanzi[i]);} else {WriteBytetoBuf(Hanzi[i]);}}OLED12864_Location(x, y + 8); //写下面一行for (i = 12; i < 24; i++) {if (Rev) {WriteBytetoBuf((~(Hanzi[i] << 4)) >> 4);} else {WriteBytetoBuf(Hanzi[i]);}}
}
/*********显示一个12X12汉字*********************
** 功能: 显示一个12X12汉字
** 参数: x:0-83 y:0-48 Hanzi[]:存放汉字数组 Rev:反白
** 返回值:无
******************************************************/
void OLED12864_DisBigCh(unsigned char x, unsigned char y, const unsigned char Hanzi[], bit Rev)
{WriteBigCh(x, y, Hanzi, Rev);Refresh(x, y, 12, 12);
}/*********显示一个12X12汉字字符串*********************
** 功能: 显示一个12X12汉字字符串
** 参数: x:0-127 y:0-63 Hanzi[][]:存放汉字数组 num:1-10 汉字个数 Rev:反白
** 返回值:无
******************************************************/
void OLED12864_DisBigChs(unsigned char x, unsigned char y, bit Rev, unsigned char num, const unsigned char Hanzi[][24])
{unsigned char i;OLED12864_Location(x, y); //写上面一行for (i = 0; i < num; i++) {WriteBigCh(x + i * 12, y, Hanzi[i], Rev);}Refresh(x, y, 12 * num, 12);
}
/高度为16的字符显示函数
/*-------写一个ASCII字符(8*16)到缓冲区------------------------------------------------
** 功能:写一个ASCII字符(8*16)到缓冲区
** 参数: temp:要显示的数字ASCII
** 返回值:无
-----------------------------------------------------------------------*/
void WriteLargeChar(unsigned char value)
{unsigned char i;for (i = 0; i < 8; i++) { //写上面一行WriteBytetoBuf(Font8x16[value - 0x20][i]);}Buff.x = Buff.x - 8; //写下面一行Buff.y = Buff.y + 8;for (i = 8; i < 16; i++) {WriteBytetoBuf(Font8x16[value - 0x20][i]);}
}
/*-------写一个反白ASCII字符(8*16)到缓冲区------------------------------------------------
** 功能:写一个反白ASCII字符(8*16)到缓冲区
** 参数: temp:要显示的数字ASCII
** 返回值:无
-----------------------------------------------------------------------*/
void WriteLargeRevChar(unsigned char value)
{unsigned char i;for (i = 0; i < 8; i++) { //写上面一行WriteBytetoBuf(~Font8x16[value - 0x20][i]);}Buff.x = Buff.x - 8; //写下面一行Buff.y = Buff.y + 8;for (i = 8; i < 16; i++) {WriteBytetoBuf(~Font8x16[value - 0x20][i]);}
}/*********显示一个8*16字符串*********************
** 功能: 刷新显示一个8*16字符串
** 参数: value:字符ASCIi Rev:是否反白
** 返回值:无
******************************************************/
void OLED12864_DisLargeChar(unsigned char value, bit Rev)
{Start.x = Buff.x; //获得开始横坐标Start.y = Buff.y; //获得开始纵坐标if (Rev) {WriteLargeRevChar(value);} else {WriteLargeChar(value);}Refresh(Start.x, Start.y, 8, 16); //刷新 指定区域
}
/*********写一个8X16字符串到缓冲区*********************
** 功能: 写一个8X16字符串到缓冲区 ,每行最多显示8个字符
** 参数: *str:字符串 Rev:反白 0:不反白
** 返回值:字符串长度
******************************************************/
unsigned char WriteLargeStr(char *str, bit Rev)
{unsigned char str_len = 0;while (*str != '\0') {if (Rev) {WriteLargeRevChar(*str++);} else {WriteLargeChar(*str++);}Buff.y = Buff.y - 8;str_len++;}return str_len; //返回字符串长度
}/*********显示一个8X16字符串*********************
** 功能: 显示一个8X16字符串
** 参数: *str:字符串 Rev:反白 0:不反白
** 返回值:字符串长度
******************************************************/
unsigned char OLED12864_DisLargeStr(unsigned char x, unsigned char y, bit Rev, char *str)
{unsigned char Width, Height, str_len;OLED12864_Location(x, y);Start.x = Buff.x; //获得开始横坐标Start.y = Buff.y;if (Rev) { //获得开始纵坐标str_len = WriteLargeStr(str, 1);} else {str_len = WriteLargeStr(str, 0);}Height = 16; //获得刷新高度Width = str_len * 8;; //获得字符串起始纵坐标Refresh(Start.x, Start.y, Width, Height); //刷新显示区域return str_len; //返回字符串长度
}
/*-------将一个变量转化为字符串并8*16显示------------------------------------------------
** 功能:将一个数字转化为字符串并显示如果要改变显示格式 就要改变sprintf函数的命令格式符如果要改变显示长度 就要改变str[]数组的长度
** 参数: temp:要显示的变量** 返回值:无
-----------------------------------------------------------------------*/
void OLED12864_LargeFormat1(unsigned char x, unsigned char y, bit Rev, unsigned int temp)
{char str[5];unsigned char L;//L=sprintf(str,"%d",temp); //产生“123″L = sprintf(str, "%04d", temp); //产生“01″ClearBuf(x, y, L * 8, 16);OLED12864_DisLargeStr(x, y, Rev, str);
}
void OLED12864_LargeFormat2(unsigned char x, unsigned char y, bit Rev, float temp)
{char str[10];unsigned char L;//L=sprintf(str,"%d",temp); //产生“123″L = sprintf(str, "%05.2fV", temp); //产生“01″ClearBuf(x, y, L * 8, 16);OLED12864_DisLargeStr(x, y, Rev, str);
}/*********写一个16X16汉字到缓冲区*********************
** 功能: 写一个16X16汉字符到缓冲区
** 参数: x:0-127 y:0-63 Hanzi[]:存放汉字数组 Rev:反白
** 返回值:无
******************************************************/
void WriteLargeCh(unsigned char x, unsigned char y, const unsigned char Hanzi[], bit Rev)
{unsigned char i;OLED12864_Location(x, y); //写上面一行for (i = 0; i < 16; i ++) {if (Rev) {WriteBytetoBuf(~Hanzi[i]);} else {WriteBytetoBuf(Hanzi[i]);}}OLED12864_Location(x, y + 8); //写下面一行for (i = 16; i < 32; i++) {if (Rev) {WriteBytetoBuf(~Hanzi[i]);} else {WriteBytetoBuf(Hanzi[i]);}}
}
/*********显示一个16X16汉字*********************
** 功能: 显示一个16X16汉字
** 参数: x:0-127 y:0-63 Hanzi[]:存放汉字数组 Rev:反白
** 返回值:无
******************************************************/
void OLED12864_DisLargeCh(unsigned char x, unsigned char y, const unsigned char Hanzi[], bit Rev)
{WriteLargeCh(x, y, Hanzi, Rev);Refresh(x, y, 16, 16);
}/*********显示一个16X16汉字字符串*********************
** 功能: 显示一个16X16汉字字符串
** 参数: x:0-127 y:0-63 Hanzi[][]:存放汉字数组 num:1-6 汉字个数 Rev:反白
** 返回值:无
******************************************************/
void OLED12864_DisLargeChStr(unsigned char x, unsigned char y, bit Rev, unsigned char num,const unsigned char Hanzi[][32])
{unsigned char i;OLED12864_Location(x, y); //写上面一行for (i = 0; i < num; i++) {WriteLargeCh(x + i * 16, y, Hanzi[i], Rev);}Refresh(x, y, 16 * num, 16);
}
///以下为画点,线,折线,矩形,圆,bmp图片函数
/*********获得一个有符号字符型数的绝对值*********************
** 功能: 获得一个有符号字符型数的绝对值
** 参数: 无
** 返回值:绝对值
******************************************************/
unsigned char CharAbs(char a)
{if ((unsigned char)a >= 128) {return 256 - a;} else {return a;}
}
/*********交换两个无符号字符型变量位置*********************
** 功能: 交换两个无符号字符型变量位置
** 参数: *a *b
** 返回值:绝对值
******************************************************/
void Swap(unsigned char *a, unsigned char *b)
{unsigned char temp;temp = *a;*a = *b;*b = temp;
}
/*********画一个点到缓冲区*********************
** 功能: 画一个点到缓冲区
** 参数: x:0-127 y:0-63
** 返回值:无
******************************************************/
void WritePoint(unsigned char x, unsigned char y)
{unsigned char row, line;row = y / 8; //获得y方向起始坐标line = y % 8;DisBuff[row][x] |= 0x01 << (line);
}
/*********显示一个点*********************
** 功能: 显示一个点
** 参数: x:0-127 y:0-63
** 返回值:无
******************************************************/
void DisPoint(unsigned char x, unsigned char y)
{WritePoint(x, y);Refresh(x, y, 1, 8);
}
/*********获得最小值*********************
** 功能: 获得最小值
** 参数: a b
** 返回值:a,b中的最小值
******************************************************/
unsigned char Min(unsigned char a, unsigned char b)
{return a <= b ? a : b;
}
/*********获得划线单位增加的大小*********************
** 功能: 获得划线单位增加的大小
** 参数: x1 x2
** 返回值:
******************************************************/
short GetUnitAdd(unsigned char x1, unsigned char x2)
{if (x1 == x2) {return 0;} else if (x2 > x1) {return 1;} else {return (-1);}
}
/*********填充缓冲区指定区域*********************
** 功能: 清空缓冲区指定区域
** 参数: x:0-127 y:0-63 Width:0-127 Height:0-63
** 返回值:无
******************************************************/
static void FillBuf(unsigned char x, unsigned char y, unsigned char Width, unsigned char Height)
{unsigned char i, j;Height = y + Height; //获得刷新的终止纵坐标Width = Width + x; //获得刷新的终止横坐标for (j = y; j < Height; j++) {for (i = x; i < Width; i++) {WritePoint(i, j); //写1到缓冲区以清除该点}}
}
/*********画一条线到缓冲区*********************
** 功能: 画一条线到缓冲区
** 参数: x1:0-127 起始点横坐标y1:0-63 起始点纵坐标x2:0-127 起始点横坐标y2:0-63 起始点纵坐标
** 返回值:无
******************************************************/
void WriteLine(unsigned char x1, unsigned char y1, unsigned char x2, unsigned char y2)
{unsigned char delt_x, delt_y, flag, i;short add_x, add_y, error;delt_x = CharAbs(x2 - x1); //计算Δx 取绝对值delt_y = CharAbs(y2 - y1); //计算Δyif (delt_y > delt_x) { //如果斜率大于1,置位flag,交换delt_x和delt_yflag = 1;Swap(&delt_x, &delt_y);} else {flag = 0;}add_x = GetUnitAdd(x1, x2); //x轴单位增量(-1,0或1)add_y = GetUnitAdd(y1, y2); //y轴单位增量(-1,0或1)error = delt_y << 1 -delt_x; //算法改进后由error=delt_y/delt_x-0.5;变为error=2*delt_x*(delt_y/delt_x-0.5)=2*delt_y-delt_x;for (i = 0; i <= delt_x; i++) { //横向扫描WritePoint(x1, y1); //画点if (error >= 0) { //进行error>0时的增量计算if (flag) { //斜率大于1的话,x轴进行增量计算x1 += add_x;} else {y1 += add_y; //斜率小于1的话,y轴进行增量计算}error -= (delt_x << 1);}if (flag) { //进行基本增良扑憧,即每次循环都会进行的增量计算//斜率大于1的话,y轴进行增量计算y1 += add_y;} else { //斜率小于1的话,x轴进行增量计算x1 += add_x;}error += (delt_y << 1);}
}
/*********显示一条线*********************
** 功能: 显示一条线
** 参数: x1:0-127 起始点横坐标y1:0-63 起始点纵坐标x2:0-127 起始点横坐标y2:0-63 起始点纵坐标
** 返回值:无
******************************************************/
void OLED12864_DisLine(unsigned char x1, unsigned char y1, unsigned char x2, unsigned char y2)
{unsigned char x, y, width, height;width = CharAbs(x2 - x1) + 1; //获得刷新宽度height = CharAbs(y2 - y1) + 1; //获得刷新高度x = Min(x1, x2); //获得刷新起始横坐标y = Min(y1, y2); //获得刷新起始纵坐标WriteLine(x1, y1, x2, y2);Refresh(x, y, width, height);
}
/*********显示折线*********************
** 功能: 显示折线
** 参数: *p:节点结构体数组例如:PolyLinecode Point PolyLine[3]={{0,0},{20,30},{40,30},};num:节点个数
** 返回值:无
******************************************************/
void OLED12864_DisPolyline(const Point *p, unsigned char num)
{unsigned char i;for (i = 0; i < num; i++) {WriteLine(p[i].x, p[i].y, p[i + 1].x, p[i + 1].y);}RefreshAll();//全部刷新显示
}/*********画矩形*********************
** 功能: 画矩形
** 参数: x1:0-127 矩形左上角横坐标y1:0-63 矩形左上角纵坐标width:0-127 矩形宽度height:0-63 矩形高度
** 返回值:无
******************************************************/
void OLED12864_DisSqu(unsigned char x, unsigned char y, unsigned char width, unsigned char height, bit Rev)
{if (x > 127) {x = 127;}if (y > 63) {y = 63;}if (Rev) {FillBuf(x, y, width, height); //范围内的空间全部显示}WriteLine(x, y, x + width, y);WriteLine(x + width, y, x + width, y + height);WriteLine(x, y, x, y + height);WriteLine(x, y + height, x + width, y + height);Refresh(x, y, width + 1, height + 1);
}/*********画圆*********************
** 功能: 画圆
** 参数: center_x:0-127 圆心横坐标center_y:0-64 圆心左上角纵坐标r:0-32 半径
** 返回值:无
******************************************************/
void OLED12864_DisCircle(unsigned char center_x, unsigned char center_y, unsigned char r)
{unsigned char x = 0, y = r;short d = 5 - (r << 2); //判别式初值4*(1.25-r)while (x <= y) {//将圆分成对称8份分别画WritePoint(center_x + x, center_y + y);WritePoint(center_x + x, center_y - y);WritePoint(center_x - x, center_y + y);WritePoint(center_x - x, center_y - y);WritePoint(center_x + y, center_y + x);WritePoint(center_x + y, center_y - x);WritePoint(center_x - y, center_y + x);WritePoint(center_x - y, center_y - x);x++;if (d < 0) { //如果d<0判别式d=d+4*(2*x+3)d += (x << 3) + 12;} else { //如果d>=0判别式d=d+4*(2*(x-y)+5)y--;d += (x << 3) - (y << 3) + 20;}}Refresh(center_x - r, center_y - r, (r << 1) + 1, (r << 1) + 1);
}/*********画Bmp图像*********************
** 功能: 画Bmp图像
** 参数: x:0-127 图像左上角横坐标y:0-63 图像左上角纵坐标width:0-128 图像宽度height:0-64 图像高度Rev: 是否反白 0:正常 1:反白bitmap[]:存放图像的数组
** 返回值:无
******************************************************/
/*void OLED12864_DisBmp(unsigned char x,unsigned char y,unsigned char width,unsigned char height,bit Rev,char bitmap[])
{unsigned int p=0;unsigned char HeightMax;unsigned char i,j;HeightMax=(height-1)/8+1;for(j=0;j<HeightMax;j++)//{OLED12864_Location(x,y+j*8);for(i=0;i<width;i++)//{if(Rev)WriteRevBytetoBuf(bitmap[p++]);elseWriteBytetoBuf(bitmap[p++]);}}Refresh(x,y,width,height);
}*/
void OLED12864_DisBmp(unsigned char x, unsigned char y, unsigned char width, unsigned char height, bit Rev,const unsigned char bitmap[])
{unsigned int p = 0;unsigned char HeightMax;unsigned char i, j, combit, temp = 0xff;HeightMax = (height - 1) / 8 + 1;combit = height % 8; //有效数据位temp <<= combit;if (Rev) {if (combit) {for (j = 0; j < HeightMax - 1; j++) { //OLED12864_Location(x, y + j * 8);for (i = 0; i < width; i++) { //WriteRevBytetoBuf(bitmap[p++]);}}OLED12864_Location(x, y + (HeightMax - 1) * 8);for (i = 0; i < width; i++) { //WriteRevBytetoBuf(bitmap[p++] | temp);}} else { //8的整数倍行for (j = 0; j < HeightMax; j++) { //OLED12864_Location(x, y + j * 8);for (i = 0; i < width; i++) { //WriteRevBytetoBuf(bitmap[p++]);}}}} else {for (j = 0; j < HeightMax; j++) { //OLED12864_Location(x, y + j * 8);for (i = 0; i < width; i++) { //WriteBytetoBuf(bitmap[p++]);}}}Refresh(x, y, width, height);
}/*********画幂函数图像*********************
** 功能: 画B幂函数图像
** 参数: x:0-127 图像左上角横坐标y:0-63 图像左上角纵坐标width:0-128 图像宽度height:0-64 图像高度MAxX:x方向的最大值 y方向最大值=xRev: 正向负向显示 0:负向 1:正向index:幂指数
** 返回值:无
******************************************************/
void OLED12864_DisPower(unsigned char x, unsigned char y, unsigned char width, unsigned char height, int MaxX, bit Rev,float index)
{unsigned char i;unsigned int DeltaX, DeltaY, LocationY;DeltaX = MaxX / width;DeltaY = MaxX / height;if (Rev) {for (i = 0; i < width; i++) {LocationY = pow(((float)i * DeltaX / 512), index) * 512; //获取Y方向的坐标LocationY = LocationY / DeltaY;if (LocationY > height) {LocationY = height;}WritePoint(x + i, y - LocationY);}Refresh(x, y - height, width, height);} else {for (i = 0; i < width; i++) {LocationY = pow(((float)i * DeltaX / 512), index) * 512; //获取Y方向的坐标LocationY = LocationY / DeltaY;if (LocationY > height) {LocationY = height;}WritePoint(x - i, y + LocationY);}Refresh(x - width, y, width, height);}
}
/*********画油门函数图像*********************
** 功能: 画B幂函数图像
** 参数: x:0-127 图像左上角横坐标y:0-63 图像左上角纵坐标width:0-128 图像宽度height:0-64 图像高度MAxX:x方向的最大值 y方向最大值=xRev: 正向负向显示 0:负向 1:正向index:幂指数kndex:比例指数
** 返回值:无
******************************************************/
void OLED12864_DisThro(unsigned char x, unsigned char y, unsigned char width, unsigned char height, int MaxX,float index, float kndex)
{unsigned char i;unsigned int DeltaX, DeltaY, LocationY;DeltaX = MaxX / width;DeltaY = MaxX / height;for (i = 0; i < width; i++) {LocationY = 1024 * kndex * pow(((float)i * DeltaX / 1024), index) + (1 - kndex) * 512;LocationY = LocationY / DeltaY;if (LocationY > height) {LocationY = height;}WritePoint(x + i, y - LocationY);}Refresh(x, y - height, width, height);
}
效果如下所示
10、定时器测试
通过查看数据手册,可以看到这个mcu的定时器如下所示
现在先来看一下基本定时器的测试,基本定时器也就是6和7,只能做一些基本的定时,这个可以用来一些系统的时钟源,下面直接贴配置的代码
void TMR6_Config(unsigned int TimerLen)
{TMR_TimeBase_T TMR_BaseConfigStruct;RCM_EnableAPB1PeriphClock(RCM_APB1_PERIPH_TMR6); //开启定时器时钟// TMR_BaseConfigStruct.clockDivision = TMR_CLOCK_DIV_1;TMR_BaseConfigStruct.counterMode = TMR_COUNTER_MODE_UP; //向上计数模式TMR_BaseConfigStruct.clockDivision = 48-1; //48 计数频率为48M/48=1M 1s/1M=1us
// TMR_BaseConfigStruct.period = 50000; //定时器重装载数值
// TMR_BaseConfigStruct.repetitionCounter = 0;TMR_ConfigTimeBase(TMR6, &TMR_BaseConfigStruct); //定时器初始化TMR6->AUTORLD=TimerLen;TMR_EnableInterrupt(TMR6, TMR_INT_UPDATE); //开启中断TMR_Enable(TMR6); //使能中断NVIC_EnableIRQRequest(TMR6_IRQn, 3);
}
上面代码开了一个基本定时器的更新中断,使用这个中断可以
就可以周期性的做一些事情了
11、电机驱动pwm测试
pwm是电机驱动里面很常见的东西了,直接贴代码吧,和stm32的比较像
void APM_MINI_TMR1_PWMOutPut_Init(void)
{TMR_TimeBase_T timeBaseConfig;TMR_OCConfig_T occonfig;GPIO_Config_T gpioconfig;/* Enable Clock*/RCM_EnableAHBPeriphClock(RCM_AHB_PERIPH_GPIOA);RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_SYSCFG);RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_TMR1);/* Connect TMR1 to CH1 */GPIO_ConfigPinAF(GPIOA, GPIO_PIN_SOURCE_8, GPIO_AF_PIN2);gpioconfig.mode = GPIO_MODE_AF;gpioconfig.outtype = GPIO_OUT_TYPE_PP;gpioconfig.pin = GPIO_PIN_8;gpioconfig.pupd = GPIO_PUPD_NO;gpioconfig.speed = GPIO_SPEED_50MHz;GPIO_Config(GPIOA, &gpioconfig);/* Set clockDivision = 1 */timeBaseConfig.clockDivision = TMR_CKD_DIV1;/* Up-counter */timeBaseConfig.counterMode = TMR_COUNTER_MODE_UP;/* Set divider = 47 .So TMR1 clock freq ~= 48/(47+1) = 1MHZ */timeBaseConfig.div = 47 ;/* Set counter = 1000 */timeBaseConfig.period = 1000;/* Repetition counter = 0x0 */timeBaseConfig.repetitionCounter = 0;TMR_ConfigTimeBase(TMR1, &timeBaseConfig);/* PWM1 mode */occonfig.OC_Mode = TMR_OC_MODE_PWM1;/* Idle State is reset */occonfig.OC_Idlestate = TMR_OCIDLESTATE_RESET;/* NIdle State is reset */occonfig.OC_NIdlestate = TMR_OCNIDLESTATE_RESET;/* Enable CH1N ouput */occonfig.OC_OutputNState = TMR_OUTPUT_NSTATE_DISABLE;/* Enable CH1 ouput */occonfig.OC_OutputState = TMR_OUTPUT_STATE_ENABLE;/* CH1 polarity is high */occonfig.OC_Polarity = TMR_OC_POLARITY_HIGH;/* CH1N polarity is high */occonfig.OC_NPolarity = TMR_OC_NPOLARITY_HIGH;/* Set compare value */occonfig.Pulse = 500;TMR_OC1Config(TMR1, &occonfig);/* Enable PWM output */TMR_EnablePWMOutputs(TMR1);/* Enable TMR1 */TMR_Enable(TMR1);
}
之后我们用这个函数来驱动,其实就是直接设置这个比较值
可以用逻辑分析仪来抓一下数据