本帖最后由 yuyy1989 于 2023-6-23 10:57 编辑
#申请原创#
4.外设测试
4.1 按键
功率底板上的2个按键都做了上拉处理,低电平触发
这里写个简单的程序来测试一下这两个按键,按下START按键LED1亮松开熄灭,按下STOP按键LED2亮松开熄灭
查看MCU板的原理图,看看按键接到了哪个IO上
代码示例,省略了LED的部分,相关代码可以从新建工程那个帖子找到
#define KEY_GPIO GPIO2
#define KEY1_PIN GPIO_Pin_11
#define KEY2_PIN GPIO_Pin_12
#define KEY_PINS KEY1_PIN|KEY2_PIN
void key_init()
{
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_StructInit(&GPIO_InitStruct);
GPIO_StructInit(&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStruct.GPIO_Pin = KEY_PINS;
GPIO_Init(KEY_GPIO, &GPIO_InitStruct);
}
void mcu_init(void)
{
__disable_irq(); /* 关闭中断 中断总开关 */
SYS_WR_PROTECT = 0x7a83; /*使能系统寄存器写操作*/
FLASH_CFG |= 0x00080000; /* enable prefetch ,FLASH预取加速使能*/
IWDG_DISABLE(); /*关闭清零看门狗*/
SYS_MclkChoice(SYS_MCLK_96M_RC); /*选择当前主时钟频率*/
SysClock = SYS_ReadMcuClk();
led_init();
key_init();
yuyy_delay_us(100); /* 延时等待硬件初始化稳定 */
SYS_WR_PROTECT = 0x0; /*关闭系统寄存器写操作*/
__enable_irq(); /* 开启总中断 */
}
int main(void)
{
mcu_init();
while (1)
{
if(Bit_RESET == GPIO_ReadInputDataBit(KEY_GPIO,KEY1_PIN))
GPIO_SetBits(LED_GPIO, LED1_PIN);
else
GPIO_ResetBits(LED_GPIO, LED1_PIN);
if(Bit_RESET == GPIO_ReadInputDataBit(KEY_GPIO,KEY2_PIN))
GPIO_SetBits(LED_GPIO, LED2_PIN);
else
GPIO_ResetBits(LED_GPIO, LED2_PIN);
}
}
运行效果
4.2 PWM输出
通过使用Timer的比较模式可以输出PWM,查看原理图,LED1和LED2的引脚正好是Timer1两个通道的输出,用这两个LED写个呼吸灯测试一下PWM输出功能
工程需添加库文件lks32mc07x_tim.c
代码示例
void pwm_gpio_init()
{
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_StructInit(&GPIO_InitStruct); //初始化结构体
//配置P0.6 UTIMER1_CH0 配置P0.7 UTIMER1_CH1
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT; //GPIO输出模式
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;
GPIO_Init(GPIO0, &GPIO_InitStruct);
GPIO_PinAFConfig(GPIO0,GPIO_PinSource_6,AF7_TIMER01); //P0.6复用为timer1的输出模式
GPIO_PinAFConfig(GPIO0,GPIO_PinSource_7,AF7_TIMER01); //P0.7复用为timer1的输出模式
}
void pwm_utimer_init(void)
{
TIM_TimerInitTypeDef TIM_InitStruct;
TIM_TimerStrutInit(&TIM_InitStruct); /* Timer结构体初始化*/
TIM_InitStruct.Timer_CH0_WorkMode = TIMER_OPMode_CMP; /* 设置Timer CH0 为比较模式 */
TIM_InitStruct.Timer_CH0Output = 0; /* 计数器回零时,比较模式输出极性控制 */
TIM_InitStruct.Timer_CH1_WorkMode = TIMER_OPMode_CMP; /* 设置Timer CH1 为比较模式 */
TIM_InitStruct.Timer_CH1Output = 0; /* 计数器回零时,比较模式输出极性控制 */
TIM_InitStruct.Timer_TH = 6000; /* 定时器计数门限初始值6000*/
TIM_InitStruct.Timer_CMP0 = 0; /* 设置比较模式的CH0比较初始值0 */
TIM_InitStruct.Timer_CMP1 = 0; /* 设置比较模式的CH1比较初始值0 */
TIM_InitStruct.Timer_FLT = 0; /* 设置捕捉模式或编码器模式下对应通道的数字滤波值 */
TIM_InitStruct.Timer_ClockDiv = TIMER_CLK_DIV16; /* 设置Timer模块时钟分频系数 */
TIM_TimerInit(UTIMER1, &TIM_InitStruct);
TIM_TimerCmd(UTIMER1, ENABLE); /* Timer1 模块使能 */
}
void mcu_init(void)
{
__disable_irq(); /* 关闭中断 中断总开关 */
SYS_WR_PROTECT = 0x7a83; /*使能系统寄存器写操作*/
FLASH_CFG |= 0x00080000; /* enable prefetch ,FLASH预取加速使能*/
IWDG_DISABLE(); /*关闭清零看门狗*/
SYS_MclkChoice(SYS_MCLK_96M_RC); /*选择当前主时钟频率*/
SysClock = SYS_ReadMcuClk();
pwm_gpio_init();
pwm_utimer_init();
yuyy_delay_us(100); /* 延时等待硬件初始化稳定 */
SYS_WR_PROTECT = 0x0; /*关闭系统寄存器写操作*/
__enable_irq(); /* 开启总中断 */
}
int main(void)
{
uint16_t pwm = 0;
uint8_t dir = 0;
mcu_init();
while (1)
{
if(dir == 0)
{
pwm++;
if(pwm == 6000)
dir = 1;
}
else
{
pwm--;
if(pwm == 0)
dir = 0;
}
TIM_CMP0(UTIMER1,pwm);
TIM_CMP1(UTIMER1,6000-pwm);
yuyy_delay_us(200);
}
}
运行效果
4.3 SPI驱动LCD屏幕
LKS32MC071有一路 SPI,支持主从模式,手里有个12864的LCD屏幕可以用SPI驱动
驱动这个屏幕需要用到5个IO CS RST A0 SCK MOSI,在原理图上尽量找没有被用到的IO
P0.14作为SPI_SCK P2.10作为SPI_MOSI P2.3作为CS P2.2作为RST P3.2作为A0
工程需添加库文件lks32mc07x_spi.c
代码示例,只列出了适配部分的代码
#include "yuyy_hs12864g18b_spi.h"
#include "yuyy_delay.h"
#include "lks32mc07x_gpio.h"
#if(!YUYY_HS12864G18B_USE_SOFT_SPI)
#include "lks32mc07x_spi.h"
#endif
//spi1 mosi P2.10
//spi1 clk P0.14
//CSPIN P2.3
//RSTPIN P2.2
//A0PIN P3.2
#define HS12864G18B_SPI_MOSI(x) x==YUYY_GPIO_LEV0?GPIO_ResetBits(GPIO2,GPIO_Pin_10):GPIO_SetBits(GPIO2,GPIO_Pin_10)
#define HS12864G18B_SPI_SCK(x) x==YUYY_GPIO_LEV0?GPIO_ResetBits(GPIO0,GPIO_Pin_14):GPIO_SetBits(GPIO0,GPIO_Pin_14)
#define HS12864G18B_SPI_CS(x) x==YUYY_GPIO_LEV0?GPIO_ResetBits(GPIO2,GPIO_Pin_3):GPIO_SetBits(GPIO2,GPIO_Pin_3)
#define HS12864G18B_SPI_RST(x) x==YUYY_GPIO_LEV0?GPIO_ResetBits(GPIO2,GPIO_Pin_2):GPIO_SetBits(GPIO2,GPIO_Pin_2)
#define HS12864G18B_SPI_A0(x) x==YUYY_GPIO_LEV0?GPIO_ResetBits(GPIO3,GPIO_Pin_2):GPIO_SetBits(GPIO3,GPIO_Pin_2)
void yuyy_hs12864g18b_spi_delayus(uint16_t us)
{
yuyy_delay_us(us);
}
void yuyy_hs12864g18b_spi_init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_StructInit(&GPIO_InitStruct);
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT; //设置为输出模式
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_10;
GPIO_Init(GPIO2, &GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_2;
GPIO_Init(GPIO3, &GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_14;
GPIO_Init(GPIO0, &GPIO_InitStruct);
#if(YUYY_HS12864G18B_USE_SOFT_SPI)
#else
SPI_InitTypeDef SPI_InitStruct;
GPIO_PinAFConfig(GPIO0, GPIO_PinSource_14, AF5_SPI); //GPIO0.14复用SPI_CLK功能
GPIO_PinAFConfig(GPIO2, GPIO_PinSource_10, AF5_SPI); //GPIO2.10复用SPI_DO功能
SPI_StructInit(&SPI_InitStruct); // SPI结构体初始化
SPI_InitStruct.Duplex = SPI_Full; //双工模式设置
SPI_InitStruct.Mode = SPI_Master; //master主机模式
SPI_InitStruct.EN = ENABLE; //使能SPI模块
SPI_InitStruct.TRANS_MODE = SPI_DMA_DISABLE; // 选择SPI搬移方式,由MCU搬运数据到SPI
SPI_InitStruct.Trig = 0; //内部自动触发传输
SPI_InitStruct.ENDIAN = SPI_FIRSTSEND_MSB; //该字节先发送 MSB
SPI_InitStruct.CPHA = 1; //第2个沿为发送数据时刻
SPI_InitStruct.CPOL = 1; //CLK默认高电平
SPI_InitStruct.BaudRate = 11; //传输速度96MHZ/(2*(11+1))= 4MHZ
SPI_InitStruct.ByteLength = 8; //发送零个字节
SPI_InitStruct.IRQEna = DISABLE; //关闭SPI各中断
SPI_Init(SPI0, &SPI_InitStruct); //SPI初始化程序
#endif
HS12864G18B_SPI_CS(YUYY_GPIO_LEV1);
}
void yuyy_hs12864g18b_spi_writebyte(uint8_t dat)
{
#if(YUYY_HS12864G18B_USE_SOFT_SPI)
uint8_t i = 0;
while(i<8)
{
HS12864G18B_SPI_SCK(YUYY_GPIO_LEV0);
if(dat & 0x80)
HS12864G18B_SPI_MOSI(YUYY_GPIO_LEV1);
else
HS12864G18B_SPI_MOSI(YUYY_GPIO_LEV0);
HS12864G18B_SPI_SCK(YUYY_GPIO_LEV1);
dat <<= 1;
i++;
}
#else
SPI_SendData(SPI0,dat);
#endif
}
void yuyy_hs12864g18b_spi_cs(YUYY_GPIO_LEV_TYPE lev)
{
yuyy_hs12864g18b_spi_delayus(5);
HS12864G18B_SPI_CS(lev);
yuyy_hs12864g18b_spi_delayus(5);
}
void yuyy_hs12864g18b_spi_rst(YUYY_GPIO_LEV_TYPE lev)
{
HS12864G18B_SPI_RST(lev);
}
void yuyy_hs12864g18b_spi_a0(YUYY_GPIO_LEV_TYPE lev)
{
HS12864G18B_SPI_A0(lev);
}
void mcu_init(void)
{
__disable_irq(); /* 关闭中断 中断总开关 */
SYS_WR_PROTECT = 0x7a83; /*使能系统寄存器写操作*/
FLASH_CFG |= 0x00080000; /* enable prefetch ,FLASH预取加速使能*/
IWDG_DISABLE(); /*关闭清零看门狗*/
SYS_MclkChoice(SYS_MCLK_96M_RC); /*选择当前主时钟频率*/
SysClock = SYS_ReadMcuClk();
yuyy_hs12864g18b_init();
yuyy_delay_us(100); /* 延时等待硬件初始化稳定 */
SYS_WR_PROTECT = 0x0; /*关闭系统寄存器写操作*/
__enable_irq(); /* 开启总中断 */
}
int main(void)
{
mcu_init();
yuyy_hs12864g18b_clear_screen();
yuyy_hs12864g18b_display_string_8x16(0,0,0,(uint8_t *)"LKS32MC071 SPI");
yuyy_hs12864g18b_display_string_8x16(0,2,0,(uint8_t *)"12864LCD TEST");
yuyy_hs12864g18b_display_string_8x16(0,4,0,(uint8_t *)"Code by yuyy1989");
yuyy_hs12864g18b_display_finish();
while (1)
{
}
}
运行效果
4.4 UART串口通讯
LKS32MC071有2路UART,功率底板上引出的是UART0,做一个简单的通讯测试,将串口发送过来的字母数字显示在LCD屏幕上
工程需添加库文件lks32mc07x_uart.c
初始化的时候发现初始化UART的结构体中断位是8位的,空闲中断是bit8,也就是没办法通过初始化UART的结构体设置空闲中断
代码示例
#define UART_BUFF_LEN 16
uint8_t uart_buff[17];
uint8_t uart_rxlen = 0;
void uart_init()
{
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_StructInit(&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_15;
GPIO_Init(GPIO0, &GPIO_InitStruct);
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
GPIO_Init(GPIO1, &GPIO_InitStruct);
GPIO_PinAFConfig(GPIO0, GPIO_PinSource_15, AF4_UART); //P0.15复用为UART_RX
GPIO_PinAFConfig(GPIO1, GPIO_PinSource_0, AF4_UART); //P1.0复用为UART_TX
UART_InitTypeDef UART_InitStruct;
UART_StructInit(&UART_InitStruct);
UART_InitStruct.BaudRate = 115200; /* 设置波特率115200 */
UART_InitStruct.WordLength = UART_WORDLENGTH_8b; /* 发送数据长度8位 */
UART_InitStruct.StopBits = UART_STOPBITS_1b; /* 停止位1位 */
UART_InitStruct.FirstSend = UART_FIRSTSEND_LSB; /* 先发送LSB */
UART_InitStruct.ParityMode = UART_Parity_NO; /* 无奇偶校验 */
//UART_InitStruct.IRQEna = UART_IRQEna_RcvOver|UART_IRQEna_IDLE; /* 空闲中断还不能这么设置 */
UART_Init(UART0, &UART_InitStruct);
UART0->IE = UART_IRQEna_RcvOver|UART_IRQEna_IDLE;//接收中断和空闲中断
NVIC_EnableIRQ(UART0_IRQn); /* 使能UART_IRQn外部中断*/
NVIC_SetPriority(UART0_IRQn, 0); /* UART_IRQn外部中断优先级设置为0*/
}
void UART0_IRQHandler(void)
{
if (UART_GetIRQFlag(UART0, UART_IF_RcvOver)) // 接收完成中断
{
UART_ClearIRQFlag(UART0, UART_IF_RcvOver); // 清除接收完成标志位
uart_buff[uart_rxlen] = UART_ReadData(UART0); // 接收 1 Byte数据
uart_rxlen++;
}
if (UART_GetIRQFlag(UART0, UART_IF_IDLE) || uart_rxlen == UART_BUFF_LEN) // 空闲中断
{
UART_ClearIRQFlag(UART0, UART_IF_IDLE); // 清除空闲标志位
while(uart_rxlen < UART_BUFF_LEN)
{
uart_buff[uart_rxlen] = ' ';
uart_rxlen++;
}
uart_buff[UART_BUFF_LEN] = '\0';
yuyy_hs12864g18b_display_string_8x16(0,6,0,uart_buff);
yuyy_hs12864g18b_display_finish();
uart_rxlen = 0;
}
}
void mcu_init(void)
{
__disable_irq(); /* 关闭中断 中断总开关 */
SYS_WR_PROTECT = 0x7a83; /*使能系统寄存器写操作*/
FLASH_CFG |= 0x00080000; /* enable prefetch ,FLASH预取加速使能*/
IWDG_DISABLE(); /*关闭清零看门狗*/
SYS_MclkChoice(SYS_MCLK_96M_RC); /*选择当前主时钟频率*/
yuyy_hs12864g18b_init();
uart_init();
yuyy_delay_us(100); /* 延时等待硬件初始化稳定 */
SYS_WR_PROTECT = 0x0; /*关闭系统寄存器写操作*/
__enable_irq(); /* 开启总中断 */
}
int main(void)
{
mcu_init();
yuyy_hs12864g18b_clear_screen();
yuyy_hs12864g18b_display_string_8x16(0,0,0,(uint8_t *)"LKS32MC071 SPI");
yuyy_hs12864g18b_display_string_8x16(0,2,0,(uint8_t *)"12864LCD TEST");
yuyy_hs12864g18b_display_string_8x16(0,4,0,(uint8_t *)"Code by yuyy1989");
yuyy_hs12864g18b_display_finish();
while (1)
{
}
}
运行效果
4.5 ADC电位器
底板上有个可调电位器,用它来测试一下ADC功能,将电位器调节后的电压用串口和LCD屏显示出来
工程需添加库文件lks32mc07x_adc.c和lks32mc07x_nvr.lib
代码示例
void adc_init()
{
ADC_InitTypeDef ADC_InitStructure;
ADC_StructInit(&ADC_InitStructure);
//ADC_InitStructure.IE = ADC_SF1_IE | ADC_SF2_IE; // 中断使能
ADC_InitStructure.RE = 0; // DMA请求使能
ADC_InitStructure.NSMP = DISABLE; // 两段采样使能
ADC_InitStructure.DATA_ALIGN = DISABLE; // 禁用DAT右对齐使能
ADC_InitStructure.CSMP = DISABLE; // 连续采样使能
ADC_InitStructure.TCNT = 1; // 触发一次采样所需的事件数
ADC_InitStructure.TROVS = ENABLE; // 手动触发过采样使能,开启后一次采样需要多次触发
ADC_InitStructure.OVSR = 0; // 过采样率
ADC_InitStructure.S1 = 4; // 第一段常规采样次数
ADC_InitStructure.S2 = 0; // 第二段常规采样次数
ADC_InitStructure.IS1 = 0; // 空闲采样次数
ADC_InitStructure.LTH = 0; // ADC 模拟看门狗 0 下阈值
ADC_InitStructure.HTH = 0; // ADC 模拟看门狗 0 上阈值
ADC_InitStructure.GEN = 0; // ADC 模拟看门狗 0 对应使能位
ADC_Init(ADC0, &ADC_InitStructure);
ADC_ClearIRQFlag(ADC0, ADC_ALL_IF);//清除所有中断标志位
ADC_CHN_GAIN_CFG(ADC0,CHN0,ADC_CHANNEL_9,ADC_GAIN3V6);
ADC_CHN_GAIN_CFG(ADC0,CHN1,ADC_CHANNEL_9,ADC_GAIN3V6);
ADC_CHN_GAIN_CFG(ADC0,CHN2,ADC_CHANNEL_9,ADC_GAIN3V6);
ADC_CHN_GAIN_CFG(ADC0,CHN3,ADC_CHANNEL_9,ADC_GAIN3V6);
}
void mcu_init(void)
{
__disable_irq(); /* 关闭中断 中断总开关 */
SYS_WR_PROTECT = 0x7a83; /*使能系统寄存器写操作*/
FLASH_CFG |= 0x00080000; /* enable prefetch ,FLASH预取加速使能*/
IWDG_DISABLE(); /*关闭清零看门狗*/
SYS_MclkChoice(SYS_MCLK_96M_RC); /*选择当前主时钟频率*/
led_init();
yuyy_hs12864g18b_init();
uart_init();
adc_init();
yuyy_delay_us(100); /* 延时等待硬件初始化稳定 */
SYS_WR_PROTECT = 0x0; /*关闭系统寄存器写操作*/
__enable_irq(); /* 开启总中断 */
}
int main(void)
{
int32_t adcval = 0;
float vol = 0;
uint8_t lcdout[17] = {0};
mcu_init();
yuyy_hs12864g18b_clear_screen();
yuyy_hs12864g18b_display_string_8x16(0,0,0,(uint8_t *)"LKS32MC071 SPI");
yuyy_hs12864g18b_display_string_8x16(0,2,0,(uint8_t *)"12864LCD TEST");
yuyy_hs12864g18b_display_string_8x16(0,4,0,(uint8_t *)"Code by yuyy1989");
yuyy_hs12864g18b_display_finish();
while (1)
{
yuyy_delay_ms(500);
ADC_SoftTrgEN(ADC0,ENABLE);
//while(!ADC_GetIRQFlag(ADC0,ADC_SF1_IF));
adcval = ADC_GetConversionValue(ADC0,DAT0) + ADC_GetConversionValue(ADC0,DAT1) + ADC_GetConversionValue(ADC0,DAT2)+ADC_GetConversionValue(ADC0,DAT3);
adcval /= 64; //右移4位相当于/16,再取平均数/4
vol = (float)adcval/2047 *3.6 / 2 * 3; //反推ZB点电压值
printf("ADC %d %d %d %d\r\n",ADC_GetConversionValue(ADC0,DAT0),ADC_GetConversionValue(ADC0,DAT1),ADC_GetConversionValue(ADC0,DAT2),ADC_GetConversionValue(ADC0,DAT3));
printf("ADC vol %.2fv",vol);
sprintf((char *)lcdout,"ADC vol %.2fv",vol);
yuyy_hs12864g18b_display_string_8x16(0,6,0,lcdout);
}
}
运行效果,我用daplink的5v输出对MCU板进行供电,用万用表实测电位器两端电源不到4.5v,ADC转换后的电压与用万用表测得电压相差0.02v左右
|
此文章已获得独家原创/原创奖标签,著作权归21ic所有,未经允许禁止转载。
|