本帖最后由 疯影17 于 2017-11-5 23:00 编辑
新手上路,请教了
开发板用的 NUCLEO-f410rb ,数码管用的4位共阳极的能串联的静态显示模块。
首先配置spi2模式为“全双工主模式”
连线
STM32 -> 数码管
SPI2_MOSI -> SDI
SPI2_SCK -> SCLK
SPI2_LOAD -> LOAD
5V -> VCC
GND -> GND
SPI2_MOSI是SPI2主机输出, SPI2_SCK是主机时钟,其中SPI2_LOAD是普通引脚PA5,只用了这三个引脚。主机输入没用,因为数码管驱动不需要。
在main.c文件中添加两个变量
- /* USER CODE BEGIN PV */
- /* Private variables ---------------------------------------------------------*/
- uint16_t add_num = 0;
- uint8_t data[] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e,0x7f}; // 数码管的段码0-f 最后一位0x7f是小数点
- /* USER CODE END PV */
复制代码 led.h头文件
- #ifndef LED_H
- #define LED_H
- /* Includes ------------------------------------------------------------------*/
- #include "stm32f4xx_hal.h"
- #include "main.h"
- /* 数码管位枚举 */
- typedef enum{
- GE_BIT,
- SHI_BIT,
- BAI_BIT,
- QIAN_BIT
- }LedBIT;
- extern uint8_t data[];
- extern SPI_HandleTypeDef hspi2;
- void hc74959_display(uint16_t num);
- #endif
复制代码
led.c
- #include "led.h"
- /* 数码管显示函数 spi2驱动
- *数码管模块是74hc595驱动的,静态显示所以有每位数码管单独一个74hc595
- */
- void hc74959_display(uint16_t num){
- uint16_t qian = num / 1000; // 解析后的千位数字
- uint16_t bai = num / 100 % 10; // 解析后的百位数字
- uint16_t shi = num /10 %10; // 解析后的十位数字
- uint16_t ge = num %10; // 解析后的个位数字
- for (uint8_t j=0;j<4;j++){
-
- switch (j){
- case GE_BIT:
- // 个位
- HAL_SPI_Transmit(&hspi2, &data[ge], 1, 1000); // SPI 输出
- break;
- case SHI_BIT:
- // 十位
- HAL_SPI_Transmit(&hspi2, &data[shi], 1, 1000);
- break;
- case BAI_BIT:
- // 百位
- HAL_SPI_Transmit(&hspi2, &data[bai], 1, 1000);
- break;
- case QIAN_BIT:
- // 千位
- HAL_SPI_Transmit(&hspi2, &data[qian], 1, 1000);
- break;
- default:
- break;
- }
- } // end for
- /* 让锁存输出一个高电平脉冲 */
- HAL_GPIO_WritePin(SPI2_LOAD_GPIO_Port, SPI2_LOAD_Pin, GPIO_PIN_SET);
- HAL_Delay(10);
- HAL_GPIO_WritePin(SPI2_LOAD_GPIO_Port, SPI2_LOAD_Pin, GPIO_PIN_RESET);
- } /* end --------- hc74959_display functions ---------------- */
复制代码
main.c 文件中的主循环
- while (1)
- {
- /* USER CODE END WHILE */
- /* USER CODE BEGIN 3 */
- HAL_Delay(1000); // 每隔1秒add_num加1
- add_num ++;
- if (add_num >=1000){// 当add_num 大于1000时,从新赋值为0
- add_num = 0;
- }
- hc74959_display(add_num); 调用led.c中的数码管显示函数
-
- }
- /* USER CODE END 3 */
复制代码 以上是所有代码。
最主要的是SPI的发送数据函数HAL_SPI_Transmit(&hspi2, &data[shi], 1, 1000);,使用方法对不对,第三个参数的意思不是很明白。
配置的是全双工主模式,但是用的HAL_SPI_Transmit()是发送函数,会不会有什么影响?
HAL_SPI_Transmit()是最后的驱动数码管的选择吗?
逻辑分析仪的显示情况
看显示状况是没什么问题。
|
HAL_SPI_Transmit(&hspi2, &data[shi], 1, 1000);
原型是这样的,
HAL_StatusTypeDef HAL_SPI_Transmit(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout)。
第三个参数是一次要连续发送的数据个数;第四个参数为最大延时时间,单元为us。
假设SPI时钟为1MHz,即1us;发送的数据长度Size为N,发送数据类型为uint8_t,那么一共要传输 N*8位。
整个传输时间就是 1us * N * 8位 =8N us,那么这个Timeout的时间就设为 N*8 us。如果数据类型是uint16_t,那么延时就是 N*16 us
评分
查看全部评分
另外不用1个字节1个字节发,可以4个字节一起发
HAL_SPI_Transmit(&hspi2, data, 4, 0xFFFF);
还有就是不用设为全双工的,设为master_transmit就可以了,你只发不收的。没必要全双工。
数据发送完毕,在LOAD端口给个信号就会把数字显示出来了。
知道了,确实是只发送就够了
74hc595
0xffff肯定是不行的。。。万一SPI错误,会导致程序卡死在那个SPI传输里!!!
不会卡死的,0xffff也不是什么大数字,也就是65秒,像类似的应用,发送不会失败的,所以这里随便设一个值就行了,除非你要发送一个巨大的数量,确定多少ms内无法发送完成,那么尽量设一个大一点的通常没啥毛病。一般都用DMA或者IT方式发送,都不需要设这个TIMEOUT的。
/*****定义部分******/
uint8_t TX_Data[2]={0xFC,0x60};//想显示0和1
uint8_t data[]={
0xFC,/*0*/
0x60,/*1*/……………….
};
uint16_t num = 0;
/****************/
/******主程序*********/
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_SPI1_Init();
while (1)
{
hc74959_display(num);
}
}
/****************/
/*****595控制部分*****/
void hc74959_display(uint16_t num)
{
{
HAL_SPI_MspInit(&hspi1);//使能SPI1
HAL_SPI_Transmit(&hspi1,TX_Data,2,100);
}
/* 让锁存输出一个高电平脉冲 */
HAL_GPIO_WritePin(LAT_GPIO_Port, LAT_Pin ,GPIO_PIN_SET);
HAL_Delay(100);
HAL_GPIO_WritePin(LAT_GPIO_Port, LAT_Pin , GPIO_PIN_RESET);
HAL_Delay(100);
HAL_GPIO_WritePin(LAT_GPIO_Port,LAT_Pin , GPIO_PIN_SET);
}
/****************/